5f323fe6e595704fee0dc7e34c2cf9a692711bdb
[p5sagit/Devel-REPL.git] / lib / Devel / REPL / Plugin / Turtles.pm
1 package Devel::REPL::Plugin::Turtles;
2 use Devel::REPL::Plugin;
3
4 use Scalar::Util qw(reftype);
5
6 use namespace::autoclean;
7
8 has default_command_prefix => (
9   isa => "RegexpRef",
10   is  => "rw",
11   default => sub { qr/\#/ },
12 );
13
14 has turtles_matchers => (
15   traits => ['Array'],
16   isa => "ArrayRef[RegexpRef|CodeRef]",
17   is  => "rw",
18   lazy => 1,
19   default => sub { my $prefix = shift->default_command_prefix; [qr/^ $prefix (\w+) \s* (.*) /x] },
20   handles => {
21     add_turtles_matcher => 'unshift',
22   },
23 );
24
25 around 'formatted_eval' => sub {
26   my $next = shift;
27   my ($self, $line, @args) = @_;
28
29   if ( my ( $command, @rest ) = $self->match_turtles($line) ) {
30     my $method = "command_$command";
31     my $expr_method = "expr_$method";
32
33     if ( my $expr_code = $self->can($expr_method) ) {
34       if ( my $read_more = $self->can("continue_reading_if_necessary") ) {
35         push @rest, $self->$read_more(pop @rest);
36       }
37       $self->$expr_code($next, @rest);
38     } elsif ( my $cmd_code = $self->can($method) ) {
39       return $self->$cmd_code($next, @rest);
40     } else {
41       unless ( $line =~ /^\s*#/ ) { # special case for comments
42         return $self->format($self->error_return("REPL Error", "Command '$command' does not exist"));
43       }
44     }
45   } else {
46     return $self->$next($line, @args);
47   }
48 };
49
50 sub match_turtles {
51   my ( $self, $line ) = @_;
52
53   foreach my $thingy ( @{ $self->turtles_matchers } ) {
54     if ( reftype $thingy eq 'CODE' ) {
55       if ( my @res = $self->$thingy($line) ) {
56         return @res;
57       }
58     } else {
59       if ( my @res = ( $line =~ $thingy ) ) {
60         return @res;
61       }
62     }
63   }
64
65   return;
66 }
67
68 1;
69
70 __END__
71
72 =head1 NAME
73
74 Devel::REPL::Plugin::Turtles - Generic command creation using a read hook
75
76 =head1 DESCRIPTION
77
78 By default, this plugin allows calling commands using a read hook
79 to detect a default_command_prefix followed by the command name,
80 say MYCMD as an example.  The actual routine to call for the
81 command is constructed by looking for subs named 'command_MYCMD'
82 or 'expr_MYCMD' and executing them.
83
84 =head2 NOTE
85
86 The C<default_command_prefix> is C<qr/\#/> so care must be taken
87 if other uses for that character are needed (e.g., '#' for the
88 shell escape character in the PDL shell.
89
90 =cut
91