in reply to Re: Dereferencing %hash that does not exist.
in thread Dereferencing %hash that does not exist.

The Dumper output from line 120 should make it clear what $exit_ref will be set to but the error message makes it clear that it is not a code reference. My guess is that my::module::exit_routine(\%modifier) doesn't return a code reference, though it is only a guess as much of your code is not presented.

Replies are listed 'Best First'.
Re^3: Dereferencing %hash that does not exist.
by perldarren (Novice) on Sep 04, 2013 at 21:51 UTC
    Hello.
    Dumper output $VAR1 = \'';
    
    If I remove %modifier and send exit => \&Hitachi::Raidcom::exit_routine there's a whole bunch of $VARS but if I try to add the argument as in this snippet, it breaks.
    
    Here is the reverse modifier sub and the dispatch table:
    
    sub reverse_modifier { my (@undo) = @{$_[0]}; my @rdis; my @rdel; my @newundo; for my $cmd (@undo) { if ( $cmd =~ /lock/ ) { push(@newundo, $cmd) } if ( $cmd =~ /disconnect/ ) { push (@rdis, $cmd) } if ( $cmd =~ /delete/ ) { push (@rdel, $cmd) } if ( $cmd =~ /unlock/ ) { push(@newundo,(@rdis,"sleep +22",@rdel,$cmd)) } } return @newundo; } my %modifier = ( reverse_modifier => \&reverse_modifier ); # Setup the log object my $log = LogSimple->new( logdir => $logdir, logfile => $logfile, logl +evel => $loglevel, verbosity => $verbosity, exit => \&Hitachi::Raidco +m::exit_routine(\%modifier) );
    This is the entire LogSimple module:
    package LogSimple; use strict; use Time::Format qw(%time %strftime %manip); use Exporter; use vars qw($VERSION @ISA @EXPORT); our @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not expo +rt # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. # This allows declaration use LogSimple ':all'; # If you do not need this, moving things directly into @EXPORT or @EXP +ORT_OK # will save memory. our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our @EXPORT_OK = ( ); our @EXPORT = qw( ); our $VERSION = '0.01'; # Preloaded methods go here. sub new { my $class = shift; my %options = @_; my $self = { _logdir => 'LogDEC_Dir', _logfile => 'logfile.log', _loglevel => '5', _verbosity => '1', _script => $0, }; if ( exists $options{'logdir'} ) { $options{'logdir'} =~ s/\///g; $self->{_logdir} = $options{'logdir'} } else { # user didn't specify logdir, tell them where the default was +created print "Default log directory: $self->{_logdir} - change it to +not see this message\n"; } if ( exists $options{'logfile'} ) { $self->{_logfile} = $options{' +logfile'} }; if ( exists $options{'loglevel'} ) { $self->{_loglevel} = $options +{'loglevel'} }; if ( exists $options{'verbosity'} ) { $self->{_verbosity} = $optio +ns{'verbosity'} }; if ( exists $options{'exit'} ) { $self->{_exit} = $options{'exit'} + }; $self->{_log} = "$self->{_logdir}/$self->{_logfile}"; unless ( -w $self->{_logdir} ) { mkdir ( $self->{_logdir}, 0700 ) || die "Unable to create log +directory $self->{_logdir}: $!"; }; bless $self, $class; return $self; } sub datetime { return $time{'dd-mm-yyyy_hh.mm.ss'} } sub inf { my ($self,$MESSAGE) = @_; my @PASS; push(@PASS,@_); push(@PASS,("","INF", 3)); wlog(@PASS); } sub wrn { my ($self,$MESSAGE) = @_; my @PASS; push(@PASS,@_); push(@PASS,("","WRN", 2)); wlog(@PASS); } sub dbg { my ($self,$MESSAGE) = @_; my @PASS; push(@PASS,@_); push(@PASS,("","DBG", 4)); wlog(@PASS); } sub raw { my ($self,$MESSAGE) = @_; my @PASS; push(@PASS,@_); push(@PASS,("","RAW", 5)); wlog(@PASS); } sub err { my ($self,$MESSAGE,$ERR) = @_; my @PASS; push(@PASS,@_); push(@PASS,("ERR", 1)); wlog(@PASS); } sub wlog { my ($self,$MESSAGE,$ERR,$LEVEL,$LOGLEVEL) = @_; my $TIME = datetime(); my $exit_ref; if ( $LOGLEVEL <= $self->{_loglevel} ) { open (LOG, ">>$self->{_log}") || warn "Unable to open log file + $self->{_log}: $!"; print LOG "$LEVEL: $TIME : $self->{_script} : $MESSAGE\n"; print "$LEVEL: $TIME : $self->{_script} : $MESSAGE\n" if ( $se +lf->{_verbosity} > 0 ); close (LOG); } if ( $ERR ) { if ( exists $self->{_exit} ) { use Data::Dumper; print Dumper $self->{_exit}; $exit_ref = $self->{_exit}; $exit_ref->($self); if ( $LOGLEVEL <= $self->{_loglevel} ) { open (LOG, ">>$self->{_log}") || warn "Unable to open log file + $self->{_log}: $!"; print LOG "$LEVEL: $TIME : $self->{_script} : $MESSAGE\n"; print "$LEVEL: $TIME : $self->{_script} : $MESSAGE\n" if ( $se +lf->{_verbosity} > 0 ); close (LOG); }; } exit $ERR } } 1;

      OK, so Dumper output $VAR1 = \''; shows that $self->{_exit} is not a code ref, as expected. You haven't shown the code of Hitachi::Raidcom::exit_routine, but with the error message and Dumper output, it is reasonably clear what is happening.

      Your code samples seem to be alternating between exit => \&Hitachi::Raidcom::exit_routine(\%modifier) and _exit => my::module::exit_routine(\%modifier), among other alternatives.

      Hitachi::Raidcom::exit_routine(\%modifier) executes the subroutine and yields the value it returns.

      &Hitachi::Raidcom::exit_routine(\%modifier) does the same. The & is optional in this case (with the arguments in parentheses) and makes no difference.

      \&Hitachi::Raidcom::exit_routine(\%modifier) also runs the subroutine and yields a reference to the value it returns. That's why dumper gives you \''. The \ indicates a reference. In this case, a reference to the empty string.

      What will probably work for you is (as AnomalousMonk suggested):

      # Setup the log object my $log = LogSimple->new( logdir => $logdir, logfile => $logfile, logl +evel => $loglevel, verbosity => $verbosity, exit => sub { Hitachi::Ra +idcom::exit_routine(\%modifier) } );

      With this initialization, $self->{_exit} should be set to a code reference: to the anonymous sub which does nothing but call Hitachi::Raidcom::exit_routine with the argument \%modifier and return whatever that sub returns. The sub isn't executed immediately. It is executed later, in sub wlog, when the code reference is de-referenced and called. But, I haven't tested...

      While this will probably work for you, I will mention closure (just one of many articles on the subject). It is a confusing feature for many, so I suggest you not worry about it immediately, but once you have this working, learn about closure before making too much use of anonymous subroutines accessing lexical variables.

        Thank you ig, the penny has dropped for me now & I am a step closer to being a better perl programmer. On the strength of my enlightenment I donated $5 to the cause. Thank you to all who assisted me.