ConnectionManager: Disable hard limit in favor of twiddled hammering values.
[thrasher.git] / perl / lib / Net / REPL / Client.pm
blobcad37ed8d740c414cd3f720dfac6d5eb4b241b98
1 package Net::REPL::Client;
2 use strict;
3 use warnings;
5 =pod
7 =head1 NAME
9 Net::REPL::Client - ReadLine + Socket to Eval Server = interactive development
11 =head1 DESCRIPTION
13 The client object connects L<Term::ReadLine> to a socket that speaks
14 the L<Net::REPL::Server> protocol. Perl code is sent over the socket
15 to be eval'd in the server process, which sends back a result for the
16 client to print.
18 Like the Server, this class can be used as-is or superclassed to
19 provide additional capabilities.
21 =head2 Methods
23 =cut
25 use base qw(Net::REPL::Base);
27 use Socket qw(AF_UNIX);
28 use Term::ReadLine;
30 =head3 new(argument => value...)
32 Arguments:
34 =over
36 =item C<socket_args>
38 Hashref of arguments for L<IO::Socket> configuration. Use C<Domain> to
39 select a socket class.
41 =item C<debug>
43 Debug level (refer to L<Net::REPL::Base>).
45 =back
47 =cut
49 sub new {
50 my $proto = shift;
51 my $class = ref($proto) || $proto;
52 my $self = {
53 'socket_args' => {},
54 'prompt' => '',
55 @_,
57 bless($self, $class);
59 my $client = $self->_create_socket(
60 'Domain' => AF_UNIX,
61 'Proto' => 'SOCK_STREAM',
62 %{$self->{'socket_args'}},
64 if (not $client) {
65 die("Can't connect client: $!\n");
67 $self->debug("Client PID $$ connected");
69 $self->{'fh'} = $client;
71 $self->setup_io();
73 return $self;
76 sub DESTROY {
77 my ($self) = @_;
79 if ($self->{'fh'}) {
80 $self->{'fh'}->close();
84 =head3 interact()
86 Run one iteration of the REPL. Returns true if the socket remains open
87 for further iterations.
89 Blocks until a line of input can be read from the terminal, sent to
90 the server, and the result received and printed.
92 =cut
94 sub interact {
95 my ($self) = @_;
97 my $input = $self->read();
98 if (not defined($input)) {
99 return 0;
101 elsif ($input eq '') {
102 return 1;
105 my $output;
106 if ($input =~ m{^/(.*)$}) {
107 # $input is a local command
108 my ($cmd, $input) = split(/\s+/, $1);
109 if ($cmd eq 'local_eval') {
110 my @output = $self->formatted_eval($input);
111 $output = "@output";
113 elsif ($cmd eq 'exit') {
114 return 0;
117 else {
118 # $input is for remote eval
119 $self->lv_send($input);
120 $output = $self->lv_receive();
121 if (not defined($output)) {
122 # Server has gone away?
123 return 0;
127 $self->print($output, "\n");
128 return 1;
131 =head3 setup_io()
133 Create the input source for L<read>() and output for L<print>().
135 =cut
137 sub setup_io {
138 my ($self) = @_;
140 $self->{'term'} ||= Term::ReadLine->new($self->{'prompt'});
141 $self->{'out_fh'} = $self->{'term'}->OUT();
144 =head3 read()
146 Read and return one line of user input.
148 =cut
150 sub read {
151 my ($self) = @_;
153 my $prompt = $self->{'prompt'} . '> ';
154 return $self->{'term'}->readline($prompt);
157 =head3 print()
159 Output the result string(s) from one L<interact>() iteration.
161 =cut
163 sub print {
164 my ($self, @output) = @_;
166 for my $s (@output) {
167 print { $self->{'out_fh'} } $s;