2015 twenty-four merry days of Perl Feed

Live programming perl with Reply

Reply - 2015-12-08

Of all the things Perl is and is not, it is most definitely a dynamic language. We don't run Perl through a compiler and then run the resulting executable, we just give perl some code and it runs it. In a language like C or Java, we'd have to rebuild every time we wanted to run a test, but Perl allows me to hit 'save' in my editor, alt-tab to my terminal and hit <up><enter> to rerun my test.

Obviously this helps speed up my test workflow enormously, but we can still do better. What if we could edit our application while it was running? This is the promise of a REPL (Read Eval Print Loop). In this article we'll be exploring a new REPL for Perl called Reply to do some live-coding.

You'll need a recent-ish perl installed as well as git if you're going to follow along

Installation

Let's try installing Reply through cpanminus with the cpanm utility (my prompt is the simple %):

    % cpanm Reply Term::ReadLine::Gnu Proc::InvokeEditor
    --> Working on Reply
    Fetching http://www.cpan.org/authors/id/D/DO/DOY/Reply-0.37.tar.gz ... OK
    Configuring Reply-0.37 ... OK
    ==> Found dependencies: Config::INI::Reader::Ordered
    --> Working on Config::INI::Reader::Ordered
    Fetching http://www.cpan.org/authors/id/R/RJ/RJBS/Config-INI-Reader-Ordered-0.020.tar.gz ... OK
    Configuring Config-INI-Reader-Ordered-0.020 ... OK
    Building and testing Config-INI-Reader-Ordered-0.020 ... OK
    Successfully installed Config-INI-Reader-Ordered-0.020
    Building and testing Reply-0.37 ... OK
    Successfully installed Reply-0.37
    2 distributions installed

Don't worry if your output looks different, so long as the modules installed successfully, you're good to go! We're also installing a bunch of other modules that are required for some of the plugins we'll try later to work.

Getting Started

Let's open a repl with the reply command:

    % reply
    /Users/user/.replyrc not found. Generating a default...
    0>

Okay, looks good so far. Let's try running some basic Perl:

    0>  $i = "foo"
    Global symbol "$i" requires explicit package name at reply input line 1.
    BEGIN not safe after errors--compilation aborted at reply input line 7.

Okay, so we're running under strict. Excellent! I also notice that readline bindings work, so you can use the arrow keys and standard readline shortcuts easily to edit your input. Autocomplete 'just works'(tm) as well (it's on the TAB key)

    1> my $i = "foo"
    $res[0] = 'foo'

Okay, the basics work. Note also that we don't need to put a semicolon at the end of a line. When you hit enter, it will treat it as a complete statement. That's an important limitation that's worth mentioning.

Let's see if we can load it into an existing project. Quit reply with Ctrl-c and find some code.

    % cd ~/code/asset-pack # my local copy of https://github.com/jjl/asset-pack.git
    % reply -Ilib # -Ilib = add 'lib' to @INC so we can see those perl modules
    0> use Asset::Pack;
    1> 

Hurray, that worked. Sadly Asset::Pack isn't useful unless you want to package an asset as a Perl file, so let's use the repl to explore List::Util:

    1> use List::Util qw(first);
    2> first {/abc/} "def", "hij"
    $res[0] = undef
    3> first {/abc/} "abc", "def"
    $res[1] = 'abc'

These two simple examples show off 'first', which takes a block. Let's look at its prototype:

    4> prototype(\&first)
    $res[2] = '&@'

Plugins Intro

At this point you can already do a fair amount. Now let's look at that .replyrc file that reply said it wrote earlier:

    # less ~/.replyrc
    script_line1 = use strict
    script_line2 = use warnings
    script_line3 = use 5.020001
    
    [Interrupt]
    [FancyPrompt]
    [DataDumper]
    [Colors]
    [ReadLine]
    [Hints]
    [Packages]
    [LexicalPersistence]
    [ResultCache]
    [Autocomplete::Packages]
    [Autocomplete::Lexicals]
    [Autocomplete::Functions]
    [Autocomplete::Globals]
    [Autocomplete::Methods]
    [Autocomplete::Commands]

Wow, that's quite a lot. Comparing against https://metacpan.org/release/Reply, I see that's most of the plugins that ship in the core distribution!

Here's what these plugins do (and what you're getting out of the box!)

Name Purpose
Interrupt Stop long-running code with ctrl-c
FancyPrompt Adds a line counter to the prompt
DataDumper Formats results with Data::Dumper
Colors Colors results
ReadLine Enables ReadLine input method (keybindings)
Hints Enables strict to work, among others (persists hints)
Packages Makes package declarations work
LexicalPersistence Makes my declarations work
ResultCache Results are put into @res for later use
Autocomplete::* Autocompletion of various types

If you don't want some of those, simply delete those lines from your config file and they won't be loaded next time you start a repl.

Take a look at https://metacpan.org/release/Reply to see all the basic plugins.

Editing multiple lines

One of the handier plugins is Reply::Plugin::Editor, which allows you to edit multiple lines in your text editor of choice. Add this to the bottom of your .replyrc:

    [Editor]
    editor=emacs # or vim, nano etc...

Now when you're in reply and you type #e, your editor will open. When you save the file and quit your editor, the code will be evaluated all at once. This allows you to define subroutines more easily because now you can split statements over multiple lines.

    0> #e
    <editor opens>
    sub hello {
      "Hello, @{[shift]}.";
    }
    <save and close>
    1> hello("world")
    $res[0]="Hello, world."

SEE ALSO

Gravatar Image This article contributed by: James Laver <james.laver@gmail.com>