NAME

POE::Component::CPAN::SQLite::Info - non-blocking wrapper around CPAN::SQLite::Info with file fetching abilities.

SYNOPSIS

use strict;
use warnings;

use POE qw(Component::CPAN::SQLite::Info);

my $poco = POE::Component::CPAN::SQLite::Info->spawn;

POE::Session->create(
    package_states => [
        main => [
            qw(
                _start
                fetched
                info
            ),
        ],
    ],
);

$poe_kernel->run;

sub _start {
    $poco->freshen( {
            mirror => 'http://cpan.org/',
            event  => 'fetched',
        }
    );
}

sub fetched {
    my ( $kernel, $input ) = @_[ KERNEL, ARG0 ];
    
    # whoops. Something whent wrong. Print the error(s)
    # and kill the component
    if ( $input->{freshen_error} ) {
        
        # if {freshen_error} says 'fetch' we got an error
        # on the network side.
        # otherwise, it's something with creating dirs for our files.
        if ( $input->{freshen_error} eq 'fetch' ) {
            # since we are fetching 3 files, we gonna have 1-3 errors here.
            print "Could not fetch file(s)\n";
            foreach my $file ( keys %{ $input->{freshen_errors} } ) {
                print "\t$file  => $input->{freshen_errors}{ $file }\n";
            }
        }
        else {
            print "Failed to create storage dir: $input->{freshen_error}\n";
        }
    }
    else {
        # we got our files, let's parse them now.
        $poco->fetch_info( { event => 'info' } );
    }
}

sub info {
    my ( $kernel, $results ) = @_[ KERNEL, ARG0 ];
    
    # $results got plenty of juicy data. Let's pick something and dump it
    use Data::Dumper;
    print Dumper ( $results->{mods}{'WWW::Search::Mininova'} );
    
    # shut the PoCo down
    $poco->shutdown;
}

Using event based interface is also possible, of course.

CONSTRUCTOR

my $poco = POE::Component::CPAN::SQLite::Info->spawn;

POE::Component::CPAN::SQLite::Info->spawn( alias => 'info' );

POE::Component::CPAN::SQLite::Info->spawn(
    alias  => 'info2',
    path   => '/tmp',
    mirror =>
    debug  => 1,
);

Returns a PoCo object. Takes five optional arguments:

alias

POE::Component::CPAN::SQLite::Info->spawn( alias => 'tube' );

Specifies a POE Kernel alias for the component.

mirror

POE::Component::CPAN::SQLite::Info->spawn( mirror => 'http://cpan.org' );

The component can prefetch the needed files for CPAN::SQLite::Info. The mirror argument specifies what CPAN mirror to get those files from. Defaults to: http://cpan.perl.org

path

POE::Component::CPAN::SQLite::Info->spawn( path => '/tmp' );

When component fetches the files needed for CPAN::SQLite::Info it will mirror them locally. By specifying the path argument you can tell the component where to store those. The component will create two directories inside the one you've specified, namely 'authors' and 'modules'. This argument defaults to 'cpan_sqlite_info' directory inside the current directory.

options

POE::Component::CPAN::SQLite::Info->spawn(
    options => {
        trace => 1,
        default => 1,
    },
);

A hashref of POE Session options to pass to the component's session.

debug

POE::Component::CPAN::SQLite::Info->spawn( debug => 1 );

When set to a true value turns on output of debug messages.

METHODS

These are the object-oriented methods of the component.

freshen

$poco->freshen( { event => 'now_files_are_fresh_event' } );

$poco->freshen( {
        event   => 'event_for_results',
        path    => '/tmp',
        mirror  => 'http://cpan.org',
        session => 'some_other_session',
        _user   => 'test',
        _foos   => 'bars',
    }
);

Takes one argument which is a hashref. See freshen event for details.

fetch_info

$poco->fetch_info( { event => 'event_for_results' } );

$poco->fetch_info( {
        event   => 'event_for_results',
        session => 'some_other_session',
        path    => '/tmp',
        _user   => 'lal',
        _moar   => 'more lal',
    }
);

Takes one argument which is a hashref. See fetch_info event for details.

session_id

my $tube_id = $poco->session_id;

Takes no arguments. Returns POE Session ID of the component.

shutdown

$poco->shutdown;

Takes no arguments. Shuts the component down.

ACCEPTED EVENTS

freshen

$poe_kernel->post( info => freshen => { event => 'event_for_results' } );

$poe_kernel->post( info => freshen => {
        event   => 'event_for_results',
        path    => '/tmp',
        mirror  => 'http://cpan.org',
        session => 'some_other_session',
        _user_defined => 'foos',
        ua_args => { timeout => 10 },
    }
);

Instructs the component to fetch the files needed by CPAN::SQLite::Info. Takes one argument which is a hashref. The argument's keys may be as follows:

event

{ event   => 'event_for_results' }

Mandatory. The name of the event to where to send the results.

mirror

{ mirror  => 'http://cpan.org' }

Optional. The mirror parameter will override the mirror parameter in the contructor. See CONSTRUCTOR section for details. Defaults to: mirror argument of the constructor.

path

{ path    => '/tmp' }

Optional. The path parameter will override the path parameter in the constructor. See CONSTRUCTOR section for description. Note: don't forget to set the same path parameter for the fetch_info, otherwise it will cry. Defaults to: path argument of the constructor.

session

{ session => 'other_session_alias' }

{ session => $other_session_ID }

{ session => $other_session_ref }

Optional. Specifies an alternative POE Session to send the output to. Accepts either session alias, session ID or session reference. Defaults to the current session.

user defined arguments

{
    _user_var    => 'foos',
    _another_one => 'bars',
    _some_other  => 'beers',
}

Optional. Any keys beginning with the _ (underscore) will be present in the output intact. If where option (see below) is specified, any arguments will also be present in the result of "finished downloading" event.

fetch_info

$poe_kernel->post( info => fetch_info => { event => 'event_for_results' } );

$poe_kernel->post( info => fetch_info => {
        event   => 'event_for_results', # mandatory
        path    => '/tmp',
        session => 'some_other_session', 
        _user   => 'lal',
        _moar   => 'more lal',
    }
);

Instructs the component to parse the CPAN files and get the information about dists, modules and authors. Takes one argument which is a hashref with the following keys:

event

{ event   => 'event_for_results' }

Mandatory. The name of the event to send the results to.

path

{ path    => '/tmp' }

Optional. The path parameter will override the path parameter in the constructor. See CONSTRUCTOR section for description. Note: don't forget to set the same path parameter for the freshen unless you have files in different locations, otherwise the poco will cry. Defaults to: path argument of the constructor.

session

{ session => 'other_session_alias' }

{ session => $other_session_ID }

{ session => $other_session_ref }

Optional. Specifies an alternative POE Session to send the output to. Accepts either session alias, session ID or session reference. Defaults to the current session.

user defined arguments

{
    _user_var    => 'foos',
    _another_one => 'bars',
    _some_other  => 'beers',
}

Optional. Any keys beginning with the _ (underscore) will be present in the output intact.

ua_args

{
    ua_args => {
        timeout => 10,
        agent   => 'CPAN Info',
    }
}

Takes a hashref as a value. Here you can specify the arguments for LWP::UserAgent constructor. If you don't specify the timeout it will default to 30 seconds. The rest of the options will default to whatever LWP::UserAgent new() method wants.

OUTPUT

The output from the component is recieved via events for both the OO and event based interface.

ouput from freshen

$VAR1 = {
    'mirror' => 'http://cpan.perl.org/',
    'files' => {
        'packages' => 'cpan_sqlite_info/modules/02packages.details.txt.gz',
        'authors' => 'cpan_sqlite_info/authors/01mailrc.txt.gz',
        'modlist' => 'cpan_sqlite_info/modules/03modlist.data.gz'
    },
    'requests' => {
        'authors' => bless( { blah }, 'HTTP::Response' ),
        'packages' => bless( { blah }, 'HTTP::Response' ),
        'modlist' => bless( { blah }, 'HTTP::Response' )
    },
    'freshen' => 1,
    'path' => 'cpan_sqlite_info/',
    'uris' => {
        'packages' => bless( do{\(my $o = 'http://cpan.perl.org/modules/02packages.details.txt.gz')}, 'URI::http' ),
        'authors' => bless( do{\(my $o = 'http://cpan.perl.org/authors/01mailrc.txt.gz')}, 'URI::http' ),
        'modlist' => bless( do{\(my $o = 'http://cpan.perl.org/modules/03modlist.data.gz')}, 'URI::http' )
    },
    ua_args => {
        'timeout' => 30,
    },
};

The event handler for the event specified in the event argument of the freshen event/method will recieve the results in ARG0 in a form of a hashref with the following keys:

mirror

{ 'mirror' => 'http://cpan.perl.org/' }

The mirror key will contain the value of the mirror argument that you provided to freshen event/method or component's constructor.

path

{ 'path' => 'cpan_sqlite_info/' }

The path key will contain the value of the path argument that you provided to freshen event/method or component's constructor.

freshen

{ 'freshen' => 1 }

The freshen key will be present, you could use it to differentiate between freshen and fetch_info results if you are getting results with the same event handler.

files

'files' => {
    'packages' => 'cpan_sqlite_info/modules/02packages.details.txt.gz',
    'authors' => 'cpan_sqlite_info/authors/01mailrc.txt.gz',
    'modlist' => 'cpan_sqlite_info/modules/03modlist.data.gz'
},

The files key will contain a hashref with the locations of three files used by CPAN::SQLite::Info. Note: locations will include the path argument (see CONSTRUCTOR).

requests

'requests' => {
    'authors' => bless( { blah }, 'HTTP::Response' ),
    'packages' => bless( { blah }, 'HTTP::Response' ),
    'modlist' => bless( { blah }, 'HTTP::Response' )
},

The <requests> key will contain a hashref with HTTP::Response objects from requests sent to fetch each of the three files used by CPAN::SQLite::Info. The names of the keys are the same as in files key (see above).

uris

'uris' => {
    'packages' => bless( do{\(my $o = 'http://cpan.perl.org/modules/02packages.details.txt.gz')}, 'URI::http' ),
    'authors' => bless( do{\(my $o = 'http://cpan.perl.org/authors/01mailrc.txt.gz')}, 'URI::http' ),
    'modlist' => bless( do{\(my $o = 'http://cpan.perl.org/modules/03modlist.data.gz')}, 'URI::http' )
}

The uris key will contain a hashref with URI objects which represent URIs used to fetch the three files used by CPAN::SQLite::Info. The names of the keys are the same as in files and requests keys (see above).

freshen_error

{ freshen_error => 'fetch' }

{ freshen_error => 'Could not make directory /root (Permission Denied)' }

The freshen_error key will exist only if an error occured. The value may be of two types. If the value contains word fetch, it means that an error occured during the download of the files and you should inspect freshen_errors (note the plural form, see description below). If the value does not contain word fetch it means the error occured during the creation of directories (including the path, see CONSTRUCTOR section). In this case, the error text will be the value of the freshen_error (note singular form) key.

freshen_errors

{
    'freshen_error' => 'fetch',
    'freshen_errors' => {
        'authors' => '500 Can\'t connect to fake.fake:80 (Bad hostname \'fake.fake\')',
        'packages' => '500 Can\'t connect to fake.fake:80 (Bad hostname \'fake.fake\')',
        'modlist' => '500 Can\'t connect to fake.fake:80 (Bad hostname \'fake.fake\')'
    },
}

When the freshen_error (note singular form) key is set to fetch the freshen_errors (note plural form) key will be present and will contain a hashref with three keys, which are the same as files, uris and requests keys (see above) and values of those keys will contain the error messages for each of the three files we were trying to fetch.

user defined arguments

{
    _user_var    => 'foos',
    _another_one => 'bars',
    _some_other  => 'beers',
}

Any keys beginning with the _ (underscore) which we passed to the freshen event/method will be present in the output intact.

ua_args

ua_args => {
    'timeout' => 30,
},

This key will contain whatever you've specified in the ua_args hashref passed to the freshen() event/method. If you didn't specify anything, it will contain one key timeout with it's default, 30 second, value.

output from fetch_info

$VAR1 = {
  'auths' => {
      'JAYBONCI' => {
          'email' => 'jay@bonci.com',
          'fullname' => 'Jay Bonci'
      },
      # lots and losts of these
  }
  'mods' => {
      'MyLibrary::DB' => {
          'dist_name' => 'MyLibrary',
          'mod_vers' => undef
      },
      # lots and losts of these
  },
  'dists' => {
      'Gtk2-Ex-VolumeButton' => {
          'dist_vers' => '0.07',
          'modules' => {
              'Gtk2::Ex::VolumeButton' => 1
              # could be more here
          },
          'cpanid' => 'FLORA',
          'dist_file' => 'Gtk2-Ex-VolumeButton-0.07.tar.gz'
      },
      # lots and losts of these
  },
  'path' => 'cpan_sqlite_info/',

The event handler set for the event you've provided to the fetch_info method/event will recieve the results in ARG0 in the form of a hashref with the followin keys:

auths

'auths' => {
    'JAYBONCI' => {
        'email' => 'jay@bonci.com',
        'fullname' => 'Jay Bonci'
    },
    # lots and losts of these
}

The auths key will contain a hashref keys of which will be CPAN authors' IDs and values will be hashrefs with two keys:

email

Contains author's email address

fullname

Contains author's full name

mods

'mods' => {
    'MyLibrary::DB' => {
        'dist_name' => 'MyLibrary',
        'mod_vers' => undef,
        # and perhaps more here
    },
    # lots and losts of these
},

The mods key will contain a hashref, keys of which will be module names and values will be hashrefs with the following keys:

dist_name

The distribution name containing the module

mod_vers

The version of the module

mod_abs

A description, if available

chapterid

The chapter ID of the module, if present

dslip

A 5 character string specifying the DSLIP (development, support, language, interface, public licence) information.

dists

'dists' => {
    'Gtk2-Ex-VolumeButton' => {
        'dist_vers' => '0.07',
        'modules' => {
            'Gtk2::Ex::VolumeButton' => 1
            # could be more here
        },
        'cpanid' => 'FLORA',
        'dist_file' => 'Gtk2-Ex-VolumeButton-0.07.tar.gz'
    },
    # lots and losts of these
},

The dists key will contain a hashref, keys of which will be distribution names and values will be hashrefs with the following keys

dist_vers

The version of the CPAN file

dist_file

The CPAN filename

cpanid

The CPAN author id

dist_abs

A description, if available

modules

Will contain a hashref which specifies the modules present in the distribution:

for my $module ( keys %{ $results->{dists}{ $distname }{modules} } ) {
  print "Module: $module\n";
}
chapterid

Specifies the chapterid and the subchapter for the distribution:

my $dist_ref = $results->{dists}{ $distname };
for my $id ( keys %{ $dist_ref->{chapterid} } ) {
    print "For chapterid $id\n";
    for my $sc ( keys %{ $dist_ref->{chapterid}{ $id } } ) {
        print "   Subchapter: $sc\n";
    }
}

path

{ 'path' => 'cpan_sqlite_info/' }

The path key will contain the path argument that you've passed to the fetch_results method/event or component's contructor.

user defined arguments

{
    _user_var    => 'foos',
    _another_one => 'bars',
    _some_other  => 'beers',
}

Optional. Any keys beginning with the _ (underscore) will be present in the output intact.

SEE ALSO

CPAN::SQLite::Info, POE

BUGS

None known. Please report, I rarely bite.

PREREQUISITES

This module requires the following modules/versions

LWP::UserAgent           => 2.036,
File::Spec               => 3.2501,
Carp                     => 1.04,
POE                      => 0.9999,
POE::Wheel::Run          => 1.2179,
POE::Filter::Reference   => 1.2187,
POE::Filter::Line        => 1.1920,
LWP::UserAgent           => 2.036,
CPAN::SQLite::Info       => 0.18

AUTHOR

Zoffix Znet, <zoffix@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2008 by Zoffix Znet

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.