Search code examples
perlmoosexml-twig

Can $self be passed to a XML::Twig handler?


I'm trying to parse different XML that is returned depending on the command given in a class method... but I think I'm getting a bit deep here.

I'd like to be able to use other methods and access attributes of the instance from WITHIN the XML::Twig handler.

This is an instance method I defined in a Moose object in order to get and parse XML using XML::Twig:

sub get_xmls {
    my $self   = shift;
    my $sehost = shift;
    my $symm   = shift;

    $self->log->info("Getting XMLs for $sehost - $symm");

    my %SYMMAPI_CALLS = (
            "Config"   => {
                'command'    => "symcfg list -sid ${symm} -v",
                'handlers'   => {
                                 'SymCLI_ML/Symmetrix' => $self->can('process_symm_info')
                            },
                'dbtable'    => "inv_emc_array"
            },
            "Pools"  => {
                'command'    => "symcfg -sid ${symm} list -pool -thin",
                'handlers'   => {
                                  'DevicePool' => $self->can('process_symm_pool')
                            },
                'dbtable'    => "inv_emc_pool"
                     }
                );

    foreach my $key (sort(keys %SYMMAPI_CALLS)) {

            my $xmldir   = $self->xmlDir;
            my $table    = $SYMMAPI_CALLS{$key}{'tbl'};
            my $handlers = $SYMMAPI_CALLS{$key}{'handlers'};
            my $command  = $SYMMAPI_CALLS{$key}{'command'};
            my $xmlfile  = qq(${xmldir}/${sehost}/${key}_${symm}.xml);

            $self->log->info("\t$key");

            if(!-d qq(${xmldir}/${sehost})) {
                mkdir(qq(${xmldir}/${sehost}))
                    or $self->log->logdie("Cant make dir ${xmldir}/${sehost}: $!");
            }

            $self->_save_symxml($command, $xmlfile);

            $self->twig(new XML::Twig( twig_handlers => $handlers ));

            $self->log->info("Parsing $xmlfile...");

            $self->twig->parsefile($xmlfile);

            $self->log->info("\t\t...finished.");
            die "Only running the first config case for now...";
    }
}

And the definition of one of the handlers (not really doing anything right now while I figure out how to do this correctly:

sub process_symm_info {
    my ($twig, $symminfo) = @_;

    print Dumper($symminfo);

}

This works just fine, but what I'd like is for the process_symm_info method to have access to $self and all the methods and attributes $self brings along with it. Is that possible? Am I doing this all wrong? Since I can specify specific parts of the XML it'd be nice to be able to do other things with that data from within the handler.

This is sort of my first venture into Perl Moose (if you couldn't already tell).


Solution

  • Currently, you have

    handlers => {
        DevicePool => $self->can('process_symm_pool'),
    },
    

    Change it to

    handlers => {
        DevicePool => sub { $self->process_symm_pool(@_) },
    },
    

    The variable $self will be captured by the anonymous sub. This is why the following works:

    sub make {
        my ($s) = @_;
        return sub { return $s };
    }
    
    my $x = make("Hello, ");
    my $y = make("World!\n");
    print $x->(), $y->();  # Hello, World!
    

    The world of closures, that is :)