Hailo::UI::ReadLine - A UI for L<Hailo|Hailo> using L<Term::ReadLine|Term::ReadLine>


Hailo documentation Contained in the Hailo distribution.

Index


Code Index:

NAME

Top

Hailo::UI::ReadLine - A UI for Hailo using Term::ReadLine

SYNOPSIS

Top

This module is called internally by Hailo, it takes no options.

A ReadLine interface will be presented when calling hailo on the command-line with only a --brain argument:

    hailo --brain hailo.sqlite

DESCRIPTION

Top

Presents a ReadLine interface using Term::ReadLine, the Term::ReadLine::Gnu frontend will be used.

AUTHOR

Top

Ævar Arnfjörð Bjarmason <avar@cpan.org>

LICENSE AND COPYRIGHT

Top


Hailo documentation Contained in the Hailo distribution.

package Hailo::UI::ReadLine;
BEGIN {
  $Hailo::UI::ReadLine::AUTHORITY = 'cpan:AVAR';
}
BEGIN {
  $Hailo::UI::ReadLine::VERSION = '0.69';
}

use 5.010;
use Any::Moose;
use Any::Moose 'X::StrictConstructor';
use Encode 'decode';
use Hailo;
use Term::ReadLine;
use Data::Dump 'dump';
use namespace::clean -except => 'meta';

with qw(Hailo::Role::Arguments
        Hailo::Role::UI);

sub BUILD {
    $ENV{PERL_RL} = 'Perl o=0' unless $ENV{PERL_RL};
    return;
}

sub run {
    my ($self, $hailo) = @_;
    my $name = 'Hailo';
    my $term = Term::ReadLine->new($name);
    my $command = qr[
                ^
                # A dot-prefix like in SQLite
                \.
                # We only have Hailo methods matching this
                (?<method> [a-z_]+ )
                # Optional arguments. These'll be passed to eval() before being
                # passed to the method
                \s*
                (?: (?<arguments>.+) )?
        $]x;

    print $self->_intro;

    while (defined (my $line = $term->readline($name . '> '))) {
        $line = decode('utf8', $line);

        given ($line) {
            when (/$command/p) {
                when ($+{method} eq 'help') {
                    print $self->_help($hailo);
                }
                when ($+{method} ~~ [ qw< quit exit >]) {
                    say $hailo->reply("Dave, this conversation can serve no purpose anymore. Goodbye.") // "Bye!";
                    exit 0;
                }
                default {
                    my $meth = $+{method};
                    my @args = defined $+{arguments} ? eval $+{arguments} : ();

                    local ($@, $!);
                    eval {
                        say dump $hailo->$meth(@args);
                    };
                    if (my $err = $@) {
                        chomp $err;
                        say STDERR "Failed on <<${^MATCH}>>: <<$err>>";
                    }
                }
            }
            default {
                my $answer = $hailo->learn_reply($line);
                say $answer // "I don't know enough to answer you yet.";
            }
        }
    }
    print "\n";

    return;
}

sub _intro {
    my ($self) = @_;
    my $intro = <<"INTRO";
Welcome to the Hailo interactive shell
Enter ".help" to show the built-in commands.
Input that's not a command will be passed to Hailo to learn, and it'll
reply back.
INTRO
    return $intro;
}

sub _help {
    my ($self, $hailo) = @_;

    my $include = qr/ ^ _go /x;
    my $exclude = qr/
                _
              (?:
                      version
                  | order
                  | progress
                  | random_reply
                  | examples
                  | autosave
                  | brain
                  | class
              )
        $/x;

    my @attr;
    for my $attr ($hailo->meta->get_all_attributes) {
        # Only get attributes that are valid command-line options
        next unless $attr->name ~~ $include;

        # We don't support changing these in mid-stream
        next if $attr->name ~~ $exclude;

        push @attr => {
            name => do {
                my $tmp = $attr->cmd_flag;
                $tmp =~ tr/-/_/;
                $tmp;
            },
            documentation => $attr->documentation,
        };
    }

    push @attr => {
        name => 'quit',
        documentation => "Exit this chat session",
    };

    my $help = <<"HELP";
These are the commands we know about:

HELP

    my @sorted = sort { $a->{name} cmp $b->{name} } @attr;
    for my $cmd (@sorted) {
        $help .= sprintf "    %-14s%s\n", '.'.$cmd->{name}, $cmd->{documentation};
    }

    $help .= <<"HELP";

The commands are just method calls on a Hailo object. Any arguments to
them will be passed through eval() used as method arguments. E.g.:

    .train "/tmp/megahal.trn"
    Trained from 350 lines in 0.54 seconds; 654.04 lines/s
    ()

Return values are printed with Data::Dump:

    .stats
    (1311, 2997, 3580, 3563)

Any input not starting with "." will be passed through Hailo's
learn_reply method:

    Hailo> Help, mommy!
    Really? I can't. It's an ethical thing.

HELP

    return $help;
}

__PACKAGE__->meta->make_immutable;