As developers, we sometimes have to help operations going smoothly by fiddling with the data "by hand" because there's no GUI to allow people doing some rare and obscure things. One common way of doing it is by connecting to the DB and writing some SQL. But often, accessing your database is not enough, because you need your application code to be run.
And for that, you need a shell.
And for that, you need a shell.
I mean a Perl application shell
Perl offers a great module to implement this: Devel::REPL . By the way, if your using a debian based distribution and if you're wondering about the quickest way to install a CPAN module, CPAN ↔ Debian is the site you want !
Let's say your application is called 'My::Bob'. In this example, it's fully implemented in the shell script itself, because well, it doesn't do much.
So here it is, the magic bob.pl shell for your My::Bob application:
use strict;
use warnings;
package My::Bob;
use Moose;
## Application bob just holds a name and a couple of methods.
has 'name' => ( is => 'rw', isa => 'Str' , default => 'Bob' );
sub hello{
my ($self) = @_;
return 'Hello, my name is '.$self->name();
}
sub count_to{
my ($self, $limit) = @_;
if( ( $limit // 0 ) < 1 ){ confess "limit should be >= 1"; }
return map{ $_ } 1..$limit;
}
package main;
## The shell code starts here
use Devel::REPL;
## You probably want to skip output buffering
$| = 1;
# Build an instance of your application.
our $BOB = My::Bob->new();
print "Hello, this is bob\n";
my $repl = Devel::REPL->new;
## Inject the instance of bob in the shell lexical environment.
$repl->load_plugin('LexEnv');
$repl->lexical_environment->do(q|my $bob = $main::BOB ;|);
## Tell something useful in the prompt
$repl->load_plugin('FancyPrompt');
$repl->fancy_prompt(sub {
my $self = shift;
sprintf ('Bob (%s) > ',
$BOB->name()
);
});
## Various autocompletion.
$repl->load_plugin('CompletionDriver::LexEnv');
$repl->load_plugin('CompletionDriver::Methods');
$repl->load_plugin('CompletionDriver::INC');
## Allow multiline statements.
$repl->load_plugin('MultiLine::PPI');
# And run!
$repl->run();
print "\nThanks for using Bob. Bye\n";
Now, let's look at a session:
$ perl bob.pl
Hello, this is bob
Bob (Bob) > $bob->hello(); ## Call any method.
Hello, my name is Bob Bob (Bob) > $bob->name('Bobbage'); ## Change of name is reflected in the prompt
Bobbage Bob (Bobbage) > $bob->count_to(3) ## Arrays are printed
1 2 3
Bob (Bobbage) > my $count_hello = sub{ my ($n) = @_; ## Define multiline subs re.pl(main):005:1* map{ $bob->hello() } $bob->count_to($n); re.pl(main):006:1* }
CODE(0x2fcbea0)
Bob (Bobbage) > &$count_hello(3) ## And call them
Hello, my name is Bobbage Hello, my name is Bobbage Hello, my name is Bobbage
Bob (Bobbage) > ## CTRL-D ends the session
Thanks for using Bob.
Hope this short example was useful to you. If you can build your application as an object, writing your own shell should be straight forward. Also you might want to add some credential checking before you let anyone playing with the guts of your application.
Until next time, happy coding!
Jerome.
$ perl bob.pl
Hello, this is bob
Bob (Bob) > $bob->hello(); ## Call any method.
Hello, my name is Bob Bob (Bob) > $bob->name('Bobbage'); ## Change of name is reflected in the prompt
Bobbage Bob (Bobbage) > $bob->count_to(3) ## Arrays are printed
1 2 3
Bob (Bobbage) > my $count_hello = sub{ my ($n) = @_; ## Define multiline subs re.pl(main):005:1* map{ $bob->hello() } $bob->count_to($n); re.pl(main):006:1* }
CODE(0x2fcbea0)
Bob (Bobbage) > &$count_hello(3) ## And call them
Hello, my name is Bobbage Hello, my name is Bobbage Hello, my name is Bobbage
Bob (Bobbage) > ## CTRL-D ends the session
Thanks for using Bob.
Hope this short example was useful to you. If you can build your application as an object, writing your own shell should be straight forward. Also you might want to add some credential checking before you let anyone playing with the guts of your application.
Until next time, happy coding!
Jerome.