More Advancements in Perl Programming
by Simon Cozens
|
Pages: 1, 2, 3, 4
Unicode
The best news about Unicode over the last year is that you should not have noticed any major changes. By now, the core Unicode support in Perl just works, and most of the CPAN modules that deal with external data have been updated to work with Unicode.
If you don't see or hear anything about Unicode, that's a good thing: it means it's all working properly.
POE
The chapter on POE was a great introduction to how POE works and some of the things that you can do with it, but it focused on using POE for networking applications and for daemons. This is only half the story. Recently a lot of interest has centered on using POE for graphical and command-line applications: Randal Schwartz takes over from the RSS aggregator at the end of the chapter by integrating it with a graphical interface in "Graphical interaction with POE and Tk." Here, I want to consider command-line applications.
The Term::Visual module is a POE component for creating applications with a split-screen interface; at the bottom of the interface, you type your input, and the output appears above a status line. The module handles all of the history, status bar updates, and everything else for you. Here's an application that uses Chatbot::Eliza to provide therapeutic session with everyone's favorite digital psychiatrist.
First, set up the chatbot and create a new Term::Visual object:
#!/usr/bin/perl -w
use POE;
use POSIX qw(strftime);
use Term::Visual;
use Chatbot::Eliza;
my $eliza = Chatbot::Eliza->new();
my $vt = Term::Visual->new( Alias => "interface" );
Now create the window, which will have space on its status bar for a clock:
my $window_id = $vt->create_window(
Status => { 0 => { format => "[%8.8s]", fields => ["time"] } },
Title => "Eliza"
);
You also need a POE::Session, which will do all the work. It will have three states; the first is the _start state, to tell Term::Visual what to do with any input it gets from the keyboard and to update the clock:
POE::Session->create
(inline_states =>
{ _start => sub {
$_[KERNEL]->post( interface => send_me_input => "got_term_input" );
$_[KERNEL]->yield( "update_time" );
},
Updating the clock is simply a matter of setting the time field declared earlier to the current time, and scheduling another update at the top of the next minute:
update_time => sub {
$vt->set_status_field( $window_id,
time => strftime("%I:%M %p", localtime) );
$_[KERNEL]->alarm( update_time => int(time() / 60) * 60 + 60 );
},
Finally, you need to handle the input from the user. Do that in a separate subroutine to make things a big clearer:
got_term_input => \&handle_term_input,
}
);
$poe_kernel->run();
When Term::Visual gets a line of text from the user, it passes it to the state declared in the _start state. The code takes that text, prints it to the terminal as an echo, and then passes it through Eliza:
sub handle_term_input {
my ($heap, $input) = @_[HEAP, ARG0];
if ($input =~ m{^/quit}i) {
$vt->delete_window($window_id);
exit;
}
$vt->print($window_id, "> $input");
$vt->print($window_id, $eliza->transform($input));
}
In just a few lines of code you have a familiar interface, similar to many IRC or MUD clients, with POE hiding all of the event handling away.

