bradcathey has asked for the wisdom of the Perl Monks concerning the following question:

Fellow Monastians,

Usually we hear about people's problems installing CPAN modules. This is a higher-view question about using a module. And I'm sure it will come down to a weak grasp of OO concepts (which I do admit, still seem magical to me), but I'm hoping that by asking this question, it will help understand both.

Of course, as a big proponent of CGI::Application I use lots of modules, but I'm having a major disconnect with one that I had installed yesterday (thank you tirwhan), WebService::ISBNDB::API. This module pulls in information from http://www.isbndb.com about any book in print, or so it seems. My goal is have a user input an ISBN number, have this module fetch the record from the service, and then populate a MySQL table by parsing the returned data about that book (I apologize if I'm not using the correct verbs). Simple enough. But here's a test:

#!/usr/bin/perl use strict; use CGI::Carp qw(fatalsToBrowser); use Data::Dumper; use WebService::ISBNDB::API::Books; my $book = WebService::ISBNDB::API->new(); my $result = WebService::ISBNDB::API::Books->search( { api_key => '6B5 +XBPOQ', isbn => '059600 +2068' } ); # thought I woul +d need $book somewhere here print "Content-type: text/plain\n\n"; print Dumper($result);
Data::Dumper returns:
$VAR1 = bless( do{\(my $o = undef)}, 'WebService::ISBNDB::Iterator' );

I thought it would return a hash with all the data about that book. And then I would use methods (the doc talks about objects, attributes and accessors) like:

my $title = $result->get_title();

to pick out specific fields. Granted, the module use Class::Std, which I don't get either. Bottomline, I just want the entire record for the book returned and then be able to extract the data I need. Are there universal principles I should know about using CPAN modules, or is this one different? Thanks in advance for your help.

—Brad
"The important work of moving the world forward does not wait to be done by perfect men." George Eliot

Replies are listed 'Best First'.
Re: Understanding how to *use* a CPAN module
by BrowserUk (Patriarch) on Apr 22, 2008 at 03:29 UTC

    If you get lost in that maze of OOO, (I did:), you might like to try something like:

    #! perl -slw use strict; use LWP::Simple; use XML::Simple; use Data::Dump qw[ pp ]; use constant ACCESS_ID => 'XXXXXXXX'; ## Your access key here. my $isbn = $ARGV[ 0 ] or die 'Need an ISBN number'; die "'$isbn' doesn't look like a valid ISBN" unless $isbn =~ m[^\d{10}$]; my $uri = sprintf "http://isbndb.com/api/books.xml?access_key=%s&index1=isbn&value1= +%s", ACCESS_ID, $isbn; my $xml = get $uri or die "Request failed"; my $info = XMLin $xml; pp $info;

    A sample usage:

    C:\test>isbndb 0131101633 { BookList => { BookData => { AuthorsText => "Brian W. Kernighan, Dennis M. Ritchie", PublisherText => { content => "Englewood Cliffs, N.J. : Prentice-Hall, c1978.", publisher_id => "prentice_hall_a01", }, Title => "The C programming language", TitleLong => {}, book_id => "the_c_programming_language", isbn => "0131101633", }, page_number => 1, page_size => 10, shown_results => 1, total_results => 1, }, server_time => "2008-04-22T03:13:35Z", }

    Wrapping that into a module with an api like:

    use ISBNDB::Simple ACCESSID => 'XXXXXXXX'; my $isbn = ...; my $href = Book( $isbn );

    Is left as an exercise :)


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      BrowserUk,

      Thanks for the "hand-rolled" version. I will be back if I can't get the aforementioned module working.

      —Brad
      "The important work of moving the world forward does not wait to be done by perfect men." George Eliot
Re: Understanding how to *use* a CPAN module
by ikegami (Patriarch) on Apr 22, 2008 at 02:51 UTC

    Class::Std is used to implement "inside-out objects", which prevents accidental (and to a large extent intentional) mucking with an object's internals. Basically, it's specifically trying to prevent you from writing the bad code you stated you wanted to write (among other things).

Re: Understanding how to *use* a CPAN module
by Limbic~Region (Chancellor) on Apr 22, 2008 at 02:03 UTC
    bradcathey,
    When in doubt, use the source. Not all implementations are equal. Some objects fully initialize upon instantiation - others only do so when you ask for data through the accessors. If you read the source and look for get_publisher() - you will see that the information isn't necessarily populated when it is called.

    Cheers - L~R

Re: Understanding how to *use* a CPAN module
by tirwhan (Abbot) on Apr 22, 2008 at 08:49 UTC

    Hi Brad :-). The reason you can't see into the objects innards is indeed its inheritance from Class::Std. Take a look at this bit from the introduction of the Class::Std POD:

    Most programmers who use Perl's object-oriented features construct their objects by blessing a hash. But, in doing so, they undermine the robustness of the OO approach. Hash-based objects are unencapsulated: their entries are open for the world to access and modify.

    So this is a feature of this particular way of doing objects. Not one I personally particularly care for (which is one of the reasons I said the usage of Class::Std-based modules is not necessarily recommended in my email), but in this case seems to be a resounding success if you are in the habit of peeking into the object in order to figure out how best to use it. The innards of an object should never matter to you as a module user, you should always access them via the published interface, i.e. the methods documented in the module POD. "Normal" (hash-based) Perl modules just trust you to do that and don't prevent you from bypassing the interface. Class::Std and its ilk protect you from yourself in that they only allow access via the interface and don't allow you to peek and prod.

    So the answer to your question on how to use a CPAN module: read the module documentation and use the module according to that. If something doesn't work, then break out Data::Dumper and maybe try to figure out why, or send a bug report to the module author that they either fix their module or the docs.


    All dogma is stupid.

      I did read what you had quoted from the docs and got some inkling of what was going on, so thanks for expanding the explanation. If you see my reply to perrin below, you will see I ran into a bug (me thinks) that was throwing me off.

      —Brad
      "The important work of moving the world forward does not wait to be done by perfect men." George Eliot
Re: Understanding how to *use* a CPAN module
by moritz (Cardinal) on Apr 22, 2008 at 08:59 UTC
    A good way to to learn a module is to read its test suite.

    Just download the tar ball, and take a look at the files in the t/ directory.

    They test what the author thinks is important, and you can run the tests easily to see if it's working (that's an advantage over the SYNOPSIS section which often leaves out some details, or contains typos and can't run when copied verbatim).

Re: Understanding how to *use* a CPAN module
by perrin (Chancellor) on Apr 22, 2008 at 12:20 UTC
    The documentation for this set of modules is a bit spread out, but you're on the right track. Your $result is an iterator object because you did a search. If you want a single book record for a specific isbn, use the example from WebService::ISBNDB::API::Books:
    my $book = WebService::ISBNDB::API->new({ api_key => $key, isbn => '0596002068' }); my $title = $book->get_title();
    The code you need is all in the docs.

      perrin,

      I had tried that and was getting zero results (white screen). When I moved the api_key up to the use declaration, I started working. Must be a bug.

      #!/usr/bin/perl use strict; use CGI::Carp qw(fatalsToBrowser); use Data::Dumper; use WebService::ISBNDB::API (api_key => '12341234'); use WebService::ISBNDB::API::Books; my $book = WebService::ISBNDB::API::Books->new('0596002068'); my $title = $book->get_title(); my $authors = $book->get_authors_text(); print "Content-type: text/plain\n\n"; print Dumper($title, $authors); 1;

      Returned:

      $VAR1 = 'Programming Web services with Perl'; $VAR2 = 'Randy J. Ray and Pavel Kulchenko';

      It really helped to look at the tests. Then the docs made more sense.

      —Brad
      "The important work of moving the world forward does not wait to be done by perfect men." George Eliot