In the last post where I experimented with readline I mentioned hacking on a REPL.
There are things like Devel::REPL that’s supposed to be ‘Modern Perl shells’, and while I’m sure they’re all great, it’s not what I wanted.
There’s a couple of things that I wanted from my REPL:
- persistent lexical variables
- fatal warnings
- tab-completion for keywords, functions and modules (internal and external)
- integrated perldoc support (why leave the shell?)
- a vi keymap
Persistent lexical variables
Persistent lexical variables was something I didn’t know I wanted before I understood what it was. The Eval::WithLexicals module by mst performs some really cool magic. To illustrate what this means, consider the following:
Let’s see what happens:
And with the use of Eval::WithLexicals:
Without the use of persistent lexicals, a REPL is no better than simply using perl with the -f flag from the command line. This allows us to use modules and write full programs in the repl, one line at a time.
Another nice module (well, ‘pragma’) by mst is strictures. It enables strict and makes all warnings fatal - a warning will cause the program to die (there’s some exceptions, which is explained in the documentation).
The tab-completion was simple, using Term::ReadLine::Gnu as described in the previous post. That post also covers how I finally managed to get a functional vi keymap.
So how would I go about getting a list of all Perl keywords? All core functions? A search for ‘keywords’ on the CPAN revealed the B::Keywords module, which exports lists of reserved barewords and symbol names. Just what I wanted.
For the perldoc integration, we simply call out to system(). For perldoc tab-completion, I wanted an updated list of modules available on the local machine. It’d be way to expensive recreating that database every single time the repl is run, so I use Storable, and added a –genmod flag for recreating it.
Storable allows us to make arbitary Perl data structures persistent by saving them them to disk.
If the hash with modules have been generated one time, and the –genmod flag is not specified, we skip the generation step and simply retrieves the structure that we saved earlier.
It was fun hacking up this little REPL. I’ve familiarized myself with several really interesting modules that I’m now using frequently.
Even though the Eval::WithLexicals module might not be that useful for other projects, it’s still a really interesting piece of code, and I’d recommend you to read the source.
The Storable module, on the other hand, is extremely useful for all kinds of tasks where a give data structure holds a not-so-dynamic dataset, and the time it takes to generate it over and over again, even though data data might still be the same, is frustrating. Storable is included in the Perl core since 5.7.3.
** Installation **
Install the required modules from the CPAN first:
Clone the git repository:
Build and install: