Devel::Command - Perl extension to automatically load and register debugger command extensions


Devel-Command documentation Contained in the Devel-Command distribution.

Index


Code Index:

NAME

Top

Devel::Command - Perl extension to automatically load and register debugger command extensions

SYNOPSIS

Top

  # in .perldb:
  use Devel::Command;
  sub afterinit {
     Devel::Command->install;
  }

DESCRIPTION

Top

Devel::Command provides a simple means to extend the Perl debugger with custom commands. It uses Module::Pluggable to locate the command modules, and installs these into a debugger global (%DB::commands).

It then searches the Devel::Command::DBSub namespace to locate an appropriate debugger patch plugin and installs it to enable the new commands.

ROUTINES

Top

import

import finds all of the command plugins for this package (i.e., any module in the Devel::Command:: namespace), calls the module's signature method to get the name of the command and its entry point, and then exports our eval subroutine into the command's namespace.

Finally, it overrides the debugger's DB::DB() subroutine with the proper patched version of that routine by calling the import() routine in each of the DB plugins in ascending version order; the last one that returns a subroutine reference is used.

cmds

A new debugger command to list the commands installed by Devel::Command.

afterinit

Does any necessary initialization for a debugger command module. Gets run after the debugger has initialized, but before the initial prompt. Calls the afterinit subroutine in each command plugin's namespace.

EXPORTED INTO PLUGINS

Top

eval

This routine is explicitly exported into the plugins so that they can call the debugger's eval routinei without having to fiddle with the bizarre calling sequence used by the debugger.

INHERITED BY SUBCLASSES

Top

signature

The signature method is common to all subclasses and is needed to handle the interfacing to this module. The default method (this one) returns a best-guess name for the command (by downcasing the last qualifier of the fully-qualified package name) and a reference to the command() subroutine in the command package itself.

Note that subclasses are free to override this method and do anything they please as long as the overrding method returns a command name and a subroutine reference to the code to be used to perform the command.

SEE ALSO

Top

perl5db.pl, notably the documentation for the DB::DB subroutine in more recent Perls (5.8.1 and later).

AUTHOR

Top

Joe McMahon, <mcmahon@ibiblio.org>

COPYRIGHT AND LICENSE

Top


Devel-Command documentation Contained in the Devel-Command distribution.

package Devel::Command;
use strict;
use warnings;
use Data::Dumper;

use Module::Pluggable search_path=>["Devel::Command"], require=>1;
use Module::Pluggable search_path=>['Devel::Command::DBSub'], 
                      sub_name => 'DB_subs';

our $VERSION = '0.11';

sub import {
  # Find and install all the plugins.
  # Uncomment the following line to verify plugin/patch loading in the debugger.
  # $DB::single=1;
  my @plugins = __PACKAGE__->plugins;
  foreach my $plugin (@plugins) {
    # Skip patch plugins.
    next if $plugin =~ /^Devel::Command::DBSub/;

    # get the signature(s) (name, entry point).
    my(@signatures) = $plugin->signature();

    # Install the command(s) in our lookup table.
    while (@signatures) {
      my $cmd_name = shift @signatures;
      my $cmd_ref  = shift @signatures;
      $DB::commands{$cmd_name} = $cmd_ref;
    }

    # Export our eval into the plugin.
    {
      no  strict 'refs';
      *{$plugin."::eval"} = \&eval;
    }
  }

  # Add our local 'cmds' command to the table.
  $DB::commands{"cmds"} = \&cmds;

  # Install the alternate version of DB::DB.  
  {
    no warnings 'redefine';
    my $patch;
    print STDERR map {"# $_"} Dumper(__PACKAGE__->DB_subs());
    foreach my $DB_module (__PACKAGE__->DB_subs) {
      my $subref;
      warn "# Trying " .Dumper($DB_module);
      if ($subref = $DB_module->import()) {
        # This module could work for the current Perl.
        $patch = [$subref, $DB_module];
      }
    }
    if (! defined $patch) {
      die "Your Perl can't be patched by Devel::Command (yours is Perl $])\n";
    }
    else {
      print "Patching with ", $patch->[1], "\n";
        *DB::DB = $patch->[0];
    }
  }
}

sub cmds {
  for my $key (keys %DB::commands) {
    print DB::OUT $key,"\n";
  }
  1;
}

sub DB::afterinit {
  my @plugins = __PACKAGE__->plugins;
  foreach my $plugin (@plugins) {
    $plugin->afterinit if $plugin->can('afterinit');
  }
}

sub eval {
  my  $arg = shift;
  $DB::evalarg = $arg;
  DB::eval();
}

sub signature {
  my $class = shift;
  # Generate a command name based on the name
  # of this plugin (the final qualifier),
  # lowercased. Assumes that the actual
  # code to execute the command is in a 
  # sub named 'command' in that package.
  (lc(substr($class,rindex($class,'::')+2)), 
   eval "\\&".$class."::command");
}

1;
__END__