# -*- coding: utf-8 -*-
# Copyright (C) 2011, 2012 Rocky Bernstein <rocky@cpan.org>
use Exporter;
use warnings;
no warnings 'redefine';
use Array::Columnize;
use Carp ();
use File::Basename;
use rlib '../../..';
use if !defined Devel::Trepan::CmdProcessor, Devel::Trepan::CmdProcessor;
use strict;
package Devel::Trepan::CmdProcessor::Command;
sub declared ($) {
use constant 1.01; # don't omit this!
my $name = shift;
$name =~ s/^::/main::/;
my $pkg = caller;
my $full_name = $name =~ /::/ ? $name : "${pkg}::$name";
$constant::declared{$full_name};
}
use vars qw(@CMD_VARS @EXPORT @ISA @CMD_ISA @ALIASES $HELP);
BEGIN {
@CMD_VARS = qw($HELP $NAME $NEED_RUNNING $NEED_STACK @CMD_VARS);
}
use vars @CMD_VARS;
@ISA = qw(Exporter);
@CMD_ISA = qw(Devel::Trepan::CmdProcessor::Command);
@EXPORT = qw(&set_name @CMD_ISA $NEED_RUNNING
$NEED_STACK @CMD_VARS declared);
use constant NEED_STACK => 0; # We'll say that commands which need a stack
# to run have to declare that and those that
# don't don't have to mention it.
# use constant NEED_RUNNING = 0; # We'll say that commands which need a a currently
# # running program. It's possible we have a stack even though
# # the program isn't running, e.g. there was an exception.
# # and we've faked the stack. (If this is not so, we can
# # don't need this and can simple use $NEED_STACK.
$HELP = 'Each command should set help text text';
use constant CATEGORY => 'Each command should set a category';
sub set_name() {
my ($pkg, $file, $line) = caller;
lc(File::Basename::basename($file, '.pm'));
}
sub new($$) {
my($class, $proc) = @_;
my $self = {
proc => $proc,
class => $class,
dbgr => $proc->{dbgr}
};
my $base_prefix="Devel::Trepan::CmdProcessor::Command::";
for my $field (@CMD_VARS) {
my $sigil = substr($field, 0, 1);
my $new_field = index('$@', $sigil) >= 0 ? substr($field, 1) : $field;
if ($sigil eq '$') {
$self->{lc $new_field} =
eval "\$${class}::${new_field} || \$${base_prefix}${new_field}";
} elsif ($sigil eq '@') {
$self->{lc $new_field} = eval "[\@${class}::${new_field}]";
} else {
die "Woah - bad sigil: $sigil";
}
}
my @ary = eval "${class}::ALIASES()";
$self->{aliases} = @ary ? [@ary] : [];
no strict 'refs';
*{"${class}::Category"} = eval "sub { ${class}::CATEGORY() }";
*{"${class}::name"} = eval "sub { \$${class}::NAME }";
my $short_help = eval "${class}::SHORT_HELP()";
$self->{short_help} = $short_help if $short_help;
bless $self, $class;
$self;
}
# List command names aligned in columns
sub columnize_commands($$) {
my ($self, $commands) = @_;
my $width = $self->settings->{maxwidth};
my $r = Array::Columnize::columnize($commands,
{displaywidth => $width,
colsep => ' ',
ljust => 1,
lineprefix => ' '});
chomp $r;
return $r;
}
sub columnize_numbers($$) {
my ($self, $commands) = @_;
my $width = $self->settings->{maxwidth};
my $r = Array::Columnize::columnize($commands,
{displaywidth => $width,
colsep => ', ',
ljust => 0,
lineprefix => ' '});
chomp $r;
return $r;
}
# FIXME: probably there is a way to do the delegation to proc methods
# without having type it all out.
sub confirm($$$) {
my ($self, $message, $default) = @_;
$self->{proc}->confirm($message, $default);
}
sub errmsg($$;$) {
my ($self, $message, $opts) = @_;
$opts ||= {};
$self->{proc}->errmsg([$message], $opts);
}
# sub obj_const($$$) {
# my ($self, $obj, $name) = @_;
# $obj->class.const_get($name)
# }
# Convenience short-hand for $self->{proc}->msg
sub msg($$;$) {
my ($self, $message, $opts) = @_;
$opts ||= {};
$self->{proc}->msg($message, $opts);
}
# Convenience short-hand for $self->{proc}->msg_nocr
sub msg_nocr($$;$) {
my ($self, $message, $opts) = @_;
$opts ||= {};
$self->{proc}->msg_nocr($message, $opts);
}
# The method that implements the debugger command.
sub run {
Carp::croak "RuntimeError: You need to define this method elsewhere";
}
sub section($$;$) {
my ($self, $message, $opts) = @_;
$opts ||={};
$self->{proc}->section($message, $opts);
}
sub settings($) {
my ($self) = @_;
$self->{proc}{settings};
}
sub short_help($) {
my ($self) = @_;
return $self->{short_help} if defined $self->{short_help};
my @ary = split("\n", $self->{help});
$self->{short_help} = $ary[0];
}
unless (caller) {
require Devel::Trepan::CmdProcessor::Mock;
my $proc = Devel::Trepan::CmdProcessor::Mock::setup();
my $cmd = Devel::Trepan::CmdProcessor::Command->new($proc);
# print $cmd->short_help, "\n";
# print $cmd, "\n";
# print $cmd->Category, "\n";
# print $cmd->{name}, "\n";
# print $cmd->MIN_ARGS, "\n";
# p cmd.complete('aa');
}
1;