File Coverage

blib/lib/IO/Prompt.pm
Criterion Covered Total %
statement 55 406 13.5
branch 4 268 1.4
condition 0 129 0.0
subroutine 15 38 39.4
pod 3 3 100.0
total 77 844 9.1


line stmt bran cond sub pod time code
1             package IO::Prompt;
2              
3             our $VERSION = '0.997002';
4              
5 1     1   38250 use strict;
  1         3  
  1         52  
6 1     1   6 use Carp;
  1         2  
  1         110  
7              
8 1     1   33 use 5.008;
  1         8  
  1         51  
9 1     1   6 no warnings 'utf8';
  1         2  
  1         104  
10              
11             our @EXPORT = qw( prompt );
12             our @EXPORT_OK = qw( hand_print get_input );
13              
14 1     1   1095 use IO::Handle;
  1         7692  
  1         65  
15 1     1   3697 use Term::ReadKey;
  1         18099  
  1         118  
16 1     1   975 use POSIX qw( isprint );
  1         7222  
  1         6  
17              
18             my $clearfirst;
19             my %input;
20              
21             sub _clear {
22 0 0   0   0 return unless $_[0];
23 0 0       0 open my $OUT, ">/dev/tty" or croak "Cannot write to terminal: $!";
24 0         0 print {$OUT} "\n" x 60;
  0         0  
25 0         0 $clearfirst = 0;
26             }
27              
28             our %flags_arg = (
29             p => 'prompt',
30             s => 'speed',
31             e => 'echo',
32             r => 'require',
33             d => 'default',
34             u => 'until',
35             w => 'while',
36             nl => 'newline',
37             m => 'menu',
38             );
39              
40             our %flags_alias = (
41             '-okayif' => '-while', '-okay_if' => '-while',
42             '-failif' => '-until', '-fail_if' => '-until',
43             );
44              
45             our %flags_noarg = (
46             y => 'yes',
47             n => 'no',
48             i => 'integer',
49             num => 'number',
50             raw => 'raw_input',
51             1 => 'onechar',
52             c => 'clear',
53             f => 'clearfirst',
54             a => 'argv',
55             l => 'line',
56             t => 'tty',
57             x => 'escape',
58             );
59              
60             my $RECORD; # store filehandle for __PROMPT__ file supporting -record flag
61              
62             $flags_arg{$_} = $_ for values %flags_arg;
63             $flags_noarg{$_} = $_ for values %flags_noarg;
64              
65             my $flag_with_arg = join '|', reverse sort keys %flags_arg;
66             my $flag_no_arg = join '|', reverse sort keys %flags_noarg;
67              
68             my %yespat = (
69             'y' => qr/^\s*[yY]/,
70             'Y' => qr/^\s*Y/,
71             );
72              
73             my %nopat = (
74             'n' => qr/^\s*[nN]/,
75             'N' => qr/^\s*N/,
76             );
77              
78             my %num_pat = (
79             integer => qr{[+-]? \d+ (?:[Ee]+?\d+ )?}x,
80             number => qr{[+-]? (?:\d+[.]?\d* | [.]\d+) (?:[Ee][+-]?\d+)? }x,
81             );
82              
83             sub _get_prompt (\%@) {
84 0     0   0 my ($flags, @data) = @_;
85 0         0 my ($OUT);
86 0 0 0     0 @data = map { $flags_alias{$_} || defined($_) ? $_ : "" } @data;
  0         0  
87 0         0 for (my $i = 0 ; $i < @data ; $i++) {
88 0         0 local *_ = \$data[$i];
89 0 0 0     0 if (ref eq 'HASH') {
    0          
    0          
90 0         0 splice @data, $i + 1, 0, %$_;
91             }
92             elsif (ref eq 'GLOB' or UNIVERSAL::isa($_, 'IO::Handle')) {
93 0 0       0 croak "Can't write prompt to read-only $_" unless -w;
94 0         0 $OUT = $_;
95             }
96             elsif (/^-/) { # a flag
97 0         0 s/_//g;
98 0 0       0 if (s/^-(f|clearfirst)/-/) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
99 0 0       0 $clearfirst = 1 unless defined $clearfirst;
100             }
101             elsif (s/^-(yes|y)/-/i) {
102 0         0 $flags->{-yesno}{yes} = $yespat{ substr $1, 0, 1 };
103 0         0 $flags->{-yesno}{yesprompt} = substr $1, 0, 1;
104             }
105             elsif (s/^-(?:nl|newline)/-/i) {
106 0         0 $flags->{-nlstr} = $data[ $i + 1 ];
107 0         0 undef $data[ $i++ ];
108             }
109             elsif (s/^-escape|-x/-/i) {
110 0         0 $flags->{-escape} = 1;
111             }
112             elsif (s/^-raw_?(?:input)?/-/i) {
113 0         0 $flags->{-raw_input} = 1;
114             }
115             elsif (s/^-number|-num/-/i) {
116 0         0 $flags->{-number} = 'number';
117             }
118             elsif (s/^-integer|-i/-/i) {
119 0         0 $flags->{-number} = 'integer';
120             }
121             elsif (s/^-(no|n)/-/i) {
122 0         0 $flags->{-yesno}{no} = $nopat{ substr $1, 0, 1 };
123 0         0 $flags->{-yesno}{noprompt} = substr $1, 0, 1;
124             }
125             elsif (m/^-($flag_with_arg)/) {
126 0 0 0     0 croak "Missing argument for $_ option" if @data < $i+2
127             || !defined $data[$i+1];
128 0         0 s/^-($flag_with_arg)/-/;
129 0         0 $flags->{ -$flags_arg{$1} } = $data[$i+1];
130 0         0 undef $data[$i++];
131             }
132             elsif (s/^-($flag_no_arg)/-/) {
133 0         0 $flags->{ -$flags_noarg{$1} } = 1;
134             }
135 0         0 else { croak "Unknown flag ($_) in prompt" }
136              
137 0 0 0     0 redo if defined $_ && /^-./;
138             }
139 0         0 else { next }
140 0         0 undef $data[$i];
141             }
142 0         0 $_ =
143             !defined() ? undef
144             : ref eq 'Regexp' ? $_
145             : qr/^\Q$_\E$/
146 0 0       0 for @{$flags}{qw(-while -until -failif -okayif)};
    0          
147              
148 0         0 for (grep { defined } $flags->{ -require }) {
  0         0  
149 0 0       0 croak "Argument to -require must be hash reference"
150             unless ref eq 'HASH';
151 0         0 my %reqs = %$_;
152             $_ = sub {
153 0     0   0 my ($input) = @_;
154 0         0 for (keys %reqs) {
155 0 0       0 return $_ unless _smartmatch($input, $reqs{$_});
156             }
157 0         0 return;
158 0         0 };
159             }
160 0         0 my @prompt = grep { defined } @data;
  0         0  
161 0 0 0     0 if (@prompt && exists $flags->{-default}) {
162 0         0 my $prompt = join "", @prompt;
163 0 0       0 $prompt =~ s/(:?\s*)$/ [$flags->{-default}]$1/ if $prompt !~ /\[.*\]/;
164 0         0 @prompt = $prompt;
165             }
166 0         0 return $OUT, @prompt;
167             }
168              
169             my $prompt_req = "(The value entered is not acceptable) ";
170              
171             sub prompt {
172 0     0 1 0 my $caller = caller;
173              
174 0         0 local $\ = q{}; # Make sure no funny business on print statements
175              
176 0         0 my %flags;
177 0         0 my ($OUT, @prompt) = _get_prompt(%flags, @_);
178 0 0 0     0 open $OUT, ">/dev/tty" or croak "Cannot write to terminal: $!" if !$OUT;
179 0         0 $OUT->autoflush(1);
180 0 0 0     0 @prompt = $flags{ -prompt } if !@prompt and $flags{ -prompt };
181 0         0 my $IN;
182 0 0 0     0 if ($flags{-tty} || $flags{-argv}) {
183 0 0       0 open $IN, "</dev/tty" or croak "Cannot read from terminal: $!";
184             }
185             else {
186 1     1   2482 use Scalar::Util;
  1         3  
  1         62  
187 1     1   4 no strict 'refs';
  1         1  
  1         99  
188 0         0 my $ARGV = $caller . "::ARGV";
189 0 0       0 unless (Scalar::Util::openhandle(*$ARGV)) {
190 0   0     0 $$ARGV = shift(@$ARGV) || '-';
191 0 0       0 open $ARGV or croak "Can't open $$ARGV: $!";
192             }
193 0         0 $IN = \*$ARGV;
194 0 0       0 @prompt = () unless -t $IN;
195             }
196 0 0       0 $flags{-speed} = 0.075 unless defined $flags{-speed};
197 1     1   5199 use Want qw( want );
  1         6333  
  1         1979  
198 0   0     0 $flags{-set_underscore} ||= want('BOOL');
199              
200 0 0 0     0 $clearfirst = 1 if !defined($clearfirst) && $flags{-clearfirst};
201 0   0     0 _clear($flags{ -clear } || $clearfirst);
202 0         0 my $input;
203 0 0 0     0 if (-t $IN and defined $input{$caller}) {
    0          
    0          
    0          
    0          
204 0         0 $input = _fake_from_DATA($caller, $IN, $OUT, \%flags, @prompt);
205             }
206             elsif ($flags{-argv}) {
207 0 0       0 return if @ARGV;
208 0 0 0     0 @prompt = "Args for $0: " if -t $IN and !@prompt;
209 0         0 print {$OUT} @prompt;
  0         0  
210 0         0 @ARGV = map glob, split /\s+/, get_input($IN, $OUT, \%flags, @prompt);
211 0         0 return @ARGV;
212             }
213             elsif ($flags{-yesno}) {
214 0         0 return _yesno($IN, $OUT, \%flags, @prompt);
215             }
216             elsif ($flags{-number}) {
217 0         0 return _number($IN, $OUT, \%flags, @prompt);
218             }
219             elsif ($flags{-menu}) {
220 0         0 return _menu($IN, $OUT, \%flags, @prompt);
221             }
222             else {
223 0         0 print {$OUT} @prompt;
  0         0  
224 0         0 $input = get_input($IN, $OUT, \%flags, @prompt);
225             }
226 0         0 return _tidy($input, %flags);
227             }
228              
229             sub _tidy {
230 0     0   0 my ($input, %flags) = @_;
231 0         0 my $defined = defined $input;
232 0 0 0     0 chomp $input if $defined && !$flags{-line};
233             my $success = $defined
234             && (!$flags{ -while } || $input =~ $flags{ -while })
235 0   0     0 && (!$flags{ -until } || $input !~ $flags{ -until });
236 0 0 0     0 print {$RECORD} $input, "\n" if $success && $RECORD;
  0         0  
237 0 0       0 return "$input" if $flags{-raw_input};
238             return bless {
239             value => $input,
240             success => $success,
241             set_val => $flags{ -set_underscore },
242             },
243 0         0 'IO::Prompt::ReturnVal';
244             }
245              
246             sub _success {
247 0     0   0 my ($val, $no_set, $raw) = @_;
248 0 0 0     0 print {$RECORD} $val, "\n" if $val && $RECORD;
  0         0  
249 0 0       0 return "$val" if $raw;
250 0         0 return bless {
251             value => $val,
252             success => 1,
253             set_val => !$no_set,
254             },
255             'IO::Prompt::ReturnVal';
256             }
257              
258             sub _failure {
259 0     0   0 my ($val, $raw) = @_;
260 0 0       0 return "$val" if $raw;
261 0         0 return bless {
262             value => $val,
263             success => 0,
264             set_val => 0,
265             },
266             'IO::Prompt::ReturnVal';
267             }
268              
269             sub import {
270 1     1   918 my $class = shift;
271              
272             {
273 1     1   13 no strict 'refs';
  1         3  
  1         957  
  1         2  
274 1         4 *{ caller() . "::$_" } = \&{$_} for @EXPORT;
  1         10  
  1         4  
275              
276 1         3 foreach my $sym (@_) {
277 0 0       0 grep { $_ eq $sym } @EXPORT_OK or next;
  0         0  
278 0         0 *{ caller() . "::$sym" } = \&{$sym};
  0         0  
  0         0  
279             }
280             }
281              
282 1         3 @_ = grep /^-/, @_;
283 1         4 $input{ caller() } = undef;
284 1 50       7 if ("@_" eq "-clearfirst") {
285 0         0 $clearfirst = 1;
286 0         0 return;
287             }
288 1         4 for my $i (0 .. $#_) {
289 0 0       0 last if $RECORD;
290 0 0       0 if ($_[$i] eq '-record') {
291 0         0 splice @_, $i, 1;
292 0 0       0 open $RECORD, '>', '__PROMPT__'
293             or croak "Can't open __PROMPT__ recording file: $!";
294 0         0 print {$RECORD} "__DATA__\n__PROMPT__\n";
  0         0  
295             }
296             }
297 1 50       16 prompt @_ if @_;
298             }
299              
300             CHECK {
301 1     1   3373 for my $pkg (keys %input) {
302 1 50       7 next if defined $input{$pkg};
303              
304 1     1   7 no strict 'refs';
  1         2  
  1         6479  
305 1 50       2 if (my $datahandle = *{"${pkg}::DATA"}{IO}) {
  1         12  
306 0         0 local $/;
307 0         0 my $data = <$datahandle>;
308 0 0       0 if ($data =~ s/(\A|\n) __PROMPT__ \s*? \n (.*)/$1/xs) {
309 0         0 $input{$pkg} = "$2";
310             }
311             else {
312 0         0 delete $input{$pkg};
313             }
314 0 0       0 open "${pkg}::DATA", "<", \$data or die "Internal error: $!";
315             }
316             else {
317 1         3210 delete $input{$pkg};
318             }
319             }
320             }
321              
322             my $baseline = ord 'A';
323              
324             sub _visualize {
325 0     0     local ($_) = @_;
326 0 0         return isprint($_) ? $_
    0          
    0          
    0          
327             : $_ eq "\n" ? $_
328             : ord($_) == 0 ? ''
329             : ord($_) < $baseline ? '^' . chr($baseline + ord($_) - 1)
330             : '?'
331             }
332              
333             sub hand_print {
334 0     0 1   my $OUT = \*STDOUT;
335 0           my $echo = undef;
336 0           my $speed = 0.05;
337 0           local $| = 1;
338 0           for (@_) {
339 0 0         if (ref eq 'HASH') {
    0          
340 0 0         $speed = $_->{-speed} if exists $_->{-speed};
341 0 0         $OUT = $_->{-to} if exists $_->{-to};
342 0 0         $echo = $_->{-echo} if exists $_->{-echo};
343             }
344             elsif (!$speed) {
345 0           print {$OUT} $_;
  0            
346             }
347             else {
348 0 0         print {$OUT} $_ and select undef, undef, undef, rand $speed
  0            
349 0   0       for map { defined $echo ? $echo : _visualize($_) } split "";
350             }
351             }
352 0           return scalar @_;
353             }
354              
355             sub _fake_from_DATA {
356 0     0     my ($caller, $IN, $OUT, $flags, @prompt) = @_;
357 0     0     local $SIG{INT} = sub { ReadMode 'restore', $IN; exit };
  0            
  0            
358 0           ReadMode 'noecho', $IN;
359 0           ReadMode 'raw', $IN;
360 0           print {$OUT} @prompt;
  0            
361 0           my $input = getc $IN;
362 0 0         if ($input =~ /\cD|\cZ/) { print {$OUT} _visualize($input),"\n"; return; }
  0            
  0            
  0            
363 0 0         if ($input eq "\e") {
364 0           ReadMode 'restore', $IN;
365 0           return get_input($IN, $OUT, $flags, @prompt);
366             }
367 0           $input{$caller} =~ m/\G (?!\cD|\cZ) (.*) (\n?)/xgc;
368 0           my ($line, $nlstr) = ($1, $2);
369 0 0         unless (defined $line) {
370 0           while ($input ne "\n") { $input = getc $IN }
  0            
371 0           print {$OUT} "\n";
  0            
372 0           return;
373             }
374 0 0         delete $input{$caller} if pos $input{$caller} == length $input{$caller};
375 0 0         if ($input eq "\n") {
376 0           hand_print { -to => $OUT, %$flags }, $line;
377 0 0         unless (defined <$IN>) { print {$OUT} "\n"; return; }
  0            
  0            
  0            
378             }
379             else {
380 0           my $i = 0;
381 0           while (1) {
382 0           my $done = $i >= length $line;
383 0 0         print {$OUT} substr($line, $i++, 1) unless $done;
  0            
384 0 0         if (getc $IN eq "\n") {
385 0 0         last if $done;
386 0           hand_print { -to => $OUT, %$flags }, substr($line, $i);
387 0           $i = length $line;
388             }
389             }
390             }
391 0           ReadMode 'restore', $IN;
392 0           print {$OUT} "\n";
  0            
393 0           return $line . $nlstr;
394             }
395              
396             sub get_input {
397 0     0 1   my ($IN, $OUT, $flags, @prompt) = @_;
398 0           my ($onechar, $nlstr, $echo, $require) =
399 0           @{$flags}{ -onechar, -nlstr, -echo, -'require' };
400 0 0         $nlstr = "\n" unless defined $nlstr;
401 0 0         if (!-t $IN) {
402 0 0         return scalar <$IN> unless $onechar;
403 0           return getc $IN;
404             }
405 0           $OUT->autoflush(1);
406 0     0     local $SIG{INT} = sub { ReadMode 'restore', $IN; exit };
  0            
  0            
407 0           my ($input, $newlines);
408 0           my %cntl = GetControlChars $IN;
409 0           my $cntl = join '|', values %cntl;
410 0           ReadMode 'raw', $IN;
411              
412 0           INPUT: while (1) {
413 0           my $next = getc $IN;
414 0 0 0       if ($next eq $cntl{INTERRUPT}) {
    0 0        
    0          
    0          
    0          
415 0           ReadMode 'restore', $IN;
416 0           exit;
417             }
418             elsif ($next eq $cntl{ERASE}) {
419 0 0 0       if (defined $input && length $input) {
420 0           substr($input, -1) = "";
421 0           print {$OUT} "\b \b";
  0            
422             }
423 0           next;
424             }
425             elsif ($next eq $cntl{EOF}) {
426 0           ReadMode 'restore', $IN;
427 0           close $IN;
428 0           return $input;
429             }
430             elsif ($flags->{-escape} && $next eq "\e") {
431 0           ReadMode 'restore', $IN;
432 0           print {$OUT} "<esc>";
  0            
433 0           return "\e";
434             }
435             elsif ($next !~ /$cntl/ && defined $next) {
436 0           $input .= $next;
437 0 0         if ($next eq "\n") {
438 0 0 0       if ($input eq "\n" && exists $flags->{-default}) {
439 0 0 0       print {$OUT} (
  0 0          
440             defined $echo
441             && $flags->{-menu} ? $echo
442             : defined $echo ? $echo x length($flags->{-default})
443             : '['.$flags->{-default}.']'
444             );
445 0           print {$OUT} $nlstr;
  0            
446 0           ReadMode 'restore', $IN;
447             return $onechar ? substr($_, 0, 1) : $_
448 0 0         for $flags->{-default};
449             }
450 0           $newlines .= $nlstr;
451             }
452             else {
453 0 0         print {$OUT}(defined $echo ? $echo : $next);
  0            
454             }
455             }
456             else {
457 0           $input .= $next;
458             }
459 0 0 0       if ($onechar or !defined $next or $input =~ m{\Q$/\E$}) {
      0        
460 0 0         chomp $input unless $flags->{-line};
461 0 0 0       if ($require and my $mesg = $require->($input)) {
462 0           print {$OUT} "\r", " " x 79, "\r", sprintf($mesg, @prompt);
  0            
463 0           undef $input;
464 0           undef $newlines;
465             }
466             else {
467 0           ReadMode 'restore', $IN;
468 0 0         print {$OUT} $newlines if defined $newlines;
  0            
469 0 0         return $onechar ? substr($input, 0, 1) : $input;
470             }
471             }
472             }
473             }
474              
475             sub _yesno {
476 0     0     my ($IN, $OUT, $flags, @prompt) = @_;
477             my ($yes, $no, $yesprompt, $noprompt) =
478 0           @{ $flags->{ -yesno } }{qw(yes no yesprompt noprompt)};
  0            
479 0 0         $yes = qr/^([^Nn])/ unless defined $yes;
480 0 0         $no = qr/^([^Yy])/ unless defined $no;
481 0 0 0       my $prompt2 =
    0          
482             $yesprompt && $noprompt ? "'$yesprompt' or '$noprompt'"
483             : $yesprompt ? "'$yesprompt' for yes"
484             : "'$noprompt' for no";
485 0           my $raw = $flags->{-raw_input};
486 0 0         print {$OUT} @prompt if -t $IN;
  0            
487 0           while (1) {
488 0           my $response =
489             get_input($IN, $OUT, { %$flags, -nlstr => "" }, @prompt);
490 0 0         chomp $response unless $flags->{-line};
491 0 0 0       print {$OUT} "\n" and return _success($response, 'no_set', $raw)
  0   0        
492             if defined $response and $response =~ /$yes/;
493 0 0 0       print {$OUT} "\n" and return _failure($response, $raw)
  0   0        
494             if !defined $response or $response =~ /$no/;
495 0 0         print {$OUT} "\r", " " x 79, "\r", @prompt,
  0            
496             "(Please answer $prompt2) "
497             if -t $IN;
498             }
499             }
500              
501             sub _number {
502 0     0     my ($IN, $OUT, $flags, @prompt) = @_;
503 0           my $numtype = $flags->{ -number };
504 0           my $prompt_num = "(Please enter a valid $numtype) ";
505 0           my $match = $num_pat{$numtype};
506 0           my $require = $flags->{ -require };
507 0 0         print {$OUT} @prompt if -t $IN;
  0            
508 0           while (1) {
509 0           my $response =
510             get_input($IN, $OUT, { %$flags, -nlstr => "", -require => undef },
511             @prompt);
512 0 0 0       chomp $response if defined $response && !$flags->{-line};
513 0 0 0       if (-t $IN and defined $response) {
514 0 0 0       if ($response !~ /\A \s* $match \s* \Z/x) {
    0          
515 0           print {$OUT} "\r", " " x 79, "\r", @prompt, $prompt_num;
  0            
516 0           next;
517             }
518             elsif ($require and my $mesg = $require->($response)) {
519 0           print {$OUT} "\r", " " x 79, "\r", sprintf($mesg, @prompt);
  0            
520 0           next;
521             }
522             }
523 0 0         print {$OUT} "\n" and return _tidy($response);
  0            
524             }
525             }
526              
527 0     0     sub _self { $_[0] }
528              
529             sub _menu {
530 0     0     my ($IN, $OUT, $flags, @prompt) = @_;
531 0           my $datatype = ref $flags->{ -menu };
532 0           my @data = $datatype eq 'ARRAY' ? @{ $flags->{ -menu } }
533 0 0         : $datatype eq 'HASH' ? sort keys %{ $flags->{ -menu } }
  0 0          
534             : croak "Argument to -menu must be hash or array reference";
535              
536             my $val_for = $datatype eq 'ARRAY'
537             ? \&_self
538 0 0   0     : sub { $flags->{ -menu }{$_[0]} };
  0            
539              
540 0           my $count = @data;
541              
542 0 0         croak "Too many -menu items" if $count > 26;
543 0 0         croak "Too few -menu items" if $count < 1;
544              
545 0           my $max_char = chr(ord('a') + $count - 1);
546 0           my $menu = q{};
547              
548 0           my $default_key;
549 0           my $next = 'a';
550 0           for (@data) {
551 0           my $item = $_;
552 0 0 0       if (defined $flags->{ -default } && !defined $default_key && $item eq $flags->{ -default }) {
      0        
553 0           $default_key = $next;
554             }
555 0           $item =~ s/\A/qq{ }.$next++.q{. }/xmse;
  0            
556 0           $item =~ s/\n?\z/\n/xms;
557 0           $item =~ s/(?!\Z)\n/\n /gxms;
558 0           $menu .= $item;
559             }
560              
561 0           push @prompt, "\n$menu\n> ";
562              
563 0           my $prompt_range = "(Please enter a-$max_char) > ";
564 0           my $require = $flags->{ -require };
565 0 0         print {$OUT} @prompt if -t $IN;
  0            
566 0           while (1) {
567 0           my $response =
568             get_input($IN, $OUT, { %$flags, -escape => 1, -nlstr => "", -require => undef },
569             @prompt);
570 0           chomp $response;
571 0 0 0       if (-t $IN and defined $response) {
572 0 0 0       if (length $response == 1 && $response eq "\e") {
    0 0        
    0 0        
      0        
573 0           return $response;
574             }
575             elsif (length $response > 1 || ($response lt 'a' || $response gt $max_char) ) {
576 0 0         if ($response ne $flags->{-default}) {
577 0           print {$OUT} "\r", " " x 79, "\r", $prompt_range;
  0            
578 0           next;
579             }
580 0           $response = $default_key;
581             }
582             elsif ($require and my $mesg = $require->($data[ord($response)-ord('a')])) {
583 0           print {$OUT} "\r", " " x 79, "\r", sprintf($mesg, @prompt);
  0            
584 0           next;
585             }
586             }
587 0           print {$OUT} "\n";
  0            
588 0           my $selection = $data[ord($response)-ord('a')];
589 0 0         $response = defined $response ? $val_for->($selection) : $response;
590 0 0 0       if (defined $response && ref($response) =~ m/\A(?:HASH|ARRAY)\z/xms ) {
591 0           $response = _menu($IN, $OUT, {%{$flags}, -menu=>$response}, "$selection: ");
  0            
592 0 0 0       if (defined $response && $response eq "\e") {
593 0 0         print {$OUT} "\n", @prompt if -t $IN;
  0            
594 0           next;
595             }
596             }
597 0           return _tidy($response);
598             }
599             }
600              
601             sub _smartmatch {
602 0     0     my ($str, $matcher) = @_;
603 0           my $type = ref $matcher;
604             my $res = $type eq 'CODE'
605 0           ? do { local $_ = $str; $matcher->() }
  0            
  0            
606             : $type eq 'Regexp' ? ($str =~ $matcher)
607 0 0         : $type eq 'ARRAY' ? scalar grep({ _smartmatch($str, $_) } @$matcher)
    0          
    0          
    0          
608             : $type eq 'HASH' ? $matcher->{$str}
609             : $str eq $matcher;
610 0           return $res;
611             }
612              
613             package IO::Prompt::ReturnVal;
614              
615             use overload
616             q{bool} => sub {
617 0 0   0   0 $_ = $_[0]{value} if $_[0]{set_val};
618 0         0 $_[0]{handled} = 1;
619 0         0 $_[0]{success};
620             },
621 0     0   0 q{""} => sub { $_[0]{handled} = 1; "$_[0]{value}"; },
  0         0  
622 0     0   0 q{0+} => sub { $_[0]{handled} = 1; 0 + $_[0]{value}; },
  0         0  
623 1         18 fallback => 1,
624 1     1   3988 ;
  1         6056  
625              
626             sub DESTROY {
627 0 0   0     $_ = $_[0]{value} unless $_[0]{handled};
628             }
629              
630             1; # Magic true value required at end of module
631             __END__
632              
633             =head1 NAME
634              
635             IO::Prompt - Interactively prompt for user input
636              
637              
638             =head1 STATUS
639              
640             This module is no longer being maintained.
641              
642             Use the IO::Prompter module instead.
643              
644              
645             =head1 VERSION
646              
647             This document describes IO::Prompt version 0.997002
648              
649             =head1 SYNOPSIS
650              
651             use IO::Prompt;
652             while( prompt "next: " ) {
653             print "You said '$_'\n";
654             }
655              
656             =head1 DESCRIPTION
657              
658             By default, this module exports a single function C<prompt>. It prompts the
659             user to enter some input, and returns an object that represents the user input.
660              
661             You may specify various flags to the function to affect its behaviour; most
662             notably, it defaults to automatically C<chomp> the input, unless the C<-line>
663             flag is specified.
664              
665             Two other functions are exported at request: C<hand_print>, which simulates
666             hand-typing to the console; and C<get_input>, which is the lower-level function
667             that actually prompts the user for a suitable input.
668              
669             Note that this is an interim re-release. A full release with better
670             documentation will follow in the near future. Meanwhile, please consult
671             the F<examples> directory from this module's CPAN distribution to better
672             understand how to make use of this module.
673            
674             =head1 INTERFACE
675              
676             =head2 Arguments to C<prompt>
677              
678             Any argument not of the following forms is treated as part of the text of the
679             prompt itself.
680              
681             Flag Long form Arg Effect
682             ---- --------- --- ------
683             <str> Use <str> as prompt
684              
685             <filehandle> Prompt to specified filehandle
686              
687             <hashref> Flatten hash entries into argument list
688             (useful for aggregating the options below)
689              
690             -p -prompt <str> Specify prompt explicitly
691              
692             -s -speed <num> Simulated typing speed (seconds/char)
693              
694             -e -echo <str> What to echo for each char typed
695              
696             -nl -newline <str> When a newline is typed, echo <str> instead
697              
698             -d -default <str> What to return if only <return> pressed
699              
700              
701             -r -require <hashref> Each value of each entry must 'smartmatch'
702             the input else corresponding key is printed
703             as error message:
704             - Subs must return true when passed input
705             - Regexes must pattern match input
706             - Strings must eq match input
707             - Arrays are flattened & recursively matched
708             - Hashes must return true for input as key
709              
710             -u -until <str|rgx> Fail if input matches <str|regex>
711             -fail_if
712              
713             -w -while <str|rgx> Fail unless input matches <str|regex>
714             -okay_if
715              
716             -m -menu <list|hash> Show the data specified as a menu
717             and allow one to be selected. Enter
718             an <ESC> to back up one level.
719              
720             -1 -one_char Return immediately after first char typed
721              
722             -x -escape Pressing <ESC> returns "\e" immediately
723              
724             -raw -raw_input Return only the string that was input
725             (turns off context-sensitive features)
726              
727             -c -clear Clear screen before prompt
728             -f -clear_first Clear screen before first prompt only
729              
730             -a -argv Load @ARGV from input if @ARGV empty
731              
732             -l -line Don't autochomp
733              
734             -t -tty Prompt to terminal no matter what
735              
736             -y -yes Return true if [yY] entered, false otherwise
737             -yn -yes_no Return true if [yY], false if [nN]
738             -Y -Yes Return true if 'Y' entered, false otherwise
739             -YN -Yes_No Return true if 'Y', false if 'N'
740              
741             -num -number Accept only valid numbers as input
742             -i -integer Accept only valid integers as input
743              
744             Note that the underscores between words in flags like C<-one_char> and
745             C<-yes_no> are optional.
746              
747             Flags can be "cuddled". For example:
748              
749             prompt("next: ", -tyn1s=>0.2) # -tty, -yes, -no, -one_char, -speed=>0.2
750              
751             =head2 "Hand-written" printing via C<hand_print()>
752              
753             The C<hand_print()> subroutine takes a string and prints it out in the
754             stop-and-start manner of hand-typed text.
755              
756             =head2 Low-level input retrieval via C<get_input()>
757              
758             The C<get_input()> subroutine is a low-level utility subroutine that
759             takes an input filehandle, an output filehandle, a reference to a hash
760             of options (as listed for C<prompt()>, above) and a single prompt
761             string. It prints the prompt and retreives the input. You almost
762             certainly want to use C<prompt()> instead.
763              
764              
765              
766             =head1 DIAGNOSTICS
767              
768             =over
769              
770             =item C<< Can't write prompt to read-only $_ >>
771              
772             You specified a filehandle to which the prompt should be written, but
773             that filehandle was not writeable. Did you pass the wrong filehandle, or
774             open it in the wrong mode?
775              
776             =item C<< Missing argument for %s option >>
777              
778             The flag you specified takes an argument, but you didn't provide that
779             argument.
780              
781             =item C<< Unknown flag ($s) in prompt >>
782              
783             The flag you specified wasn't one of those that C<prompt()> understands. Did
784             you misspell it, perhaps?
785              
786             =item C<< Argument to -require must be hash reference >>
787              
788             The C<-require> option takes a single argument that is a hash. You tried to
789             pass it something else. Try a hash instead.
790              
791             =item C<< Cannot write to terminal: %s >>
792              
793             =item C<< Cannot read from terminal: %s >>
794              
795             C<prompt()> attempted to access the terminal but couldn't. This may mean your
796             environment has no C</dev/tty> available, in which case there isn't much you
797             can do with this module. Sorry.
798              
799             =item C<< Can't open %s: %s >>
800              
801             C<prompt()> tried to read input via C<*ARGV> from a file specified on the
802             command-line, but the file couldn't be opened for the reason shown. This is
803             usually either a permission problem, a non-existent file, or a mistyped
804             filepath.
805              
806            
807             =item C<< Argument to -menu must be hash or array reference >>
808              
809             The C<-menu> option requires an argument that is either an array:
810              
811             prompt -menu=>['yes', 'no', 'maybe'];
812              
813             or a hash:
814              
815             prompt -menu=>{yes=>1, no=>0, maybe=>0.5};
816              
817             or a hash of hashes (of hashes (of array))
818              
819             =item C<< Too many -menu items >>
820              
821             =item C<< Too few -menu items >>
822              
823             A menu can't have fewer than 1 or more than 26 items.
824              
825             =back
826              
827              
828             =head1 CONFIGURATION AND ENVIRONMENT
829              
830             IO::Prompt requires no configuration files or environment variables.
831              
832              
833             =head1 DEPENDENCIES
834              
835             IO::Prompt requires the following modules:
836              
837             =over
838              
839             =item *
840              
841             version
842              
843             =item *
844              
845             IO::Handle
846              
847             =item *
848              
849             Term::ReadKey
850              
851             =item *
852              
853             POSIX
854              
855             =back
856              
857              
858             =head1 INCOMPATIBILITIES
859              
860             The module requires a /dev/tty device be available. It is therefore
861             incompatible with any system that doesn't provide such a device.
862              
863              
864             =head1 BUGS AND LIMITATIONS
865              
866             No bugs have been reported.
867              
868             Please report any bugs or feature requests to
869             C<bug-io-prompt@rt.cpan.org>, or through the web interface at
870             L<http://rt.cpan.org>.
871              
872              
873             =head1 FAQ
874              
875             This is a collection of things that might help. Please send your
876             questions that are not answered here to Damian Conway
877             C<< <DCONWAY@cpan.org> >>
878              
879             =head2 Can I use this module with ActivePerl on Windows?
880              
881             Up to now, the answer was 'No', but this has changed.
882              
883             You still cannot use ActivePerl, but if you use the Cygwin environment
884             (http://sources.redhat.com), which brings its own perl, and have
885             the latest IO::Tty (v0.05 or later) installed, it should work (feedback
886             appreciated).
887              
888              
889             =head1 THANKS
890              
891             My deepest gratitude to Autrijus Tang and Brian Ingerson, who have taken
892             care of this module for the past twelve months, while I was off trekking
893             in the highlands of Perl 6. Now it's their turn for some mountain air,
894             I'll be looking after this module again.
895              
896              
897             =head1 AUTHOR
898              
899             Damian Conway C<< <DCONWAY@cpan.org> >>
900              
901              
902             =head1 LICENCE AND COPYRIGHT
903              
904             Copyright (c) 2005, Damian Conway C<< <DCONWAY@cpan.org> >>. All rights reserved.
905              
906             This module is free software; you can redistribute it and/or
907             modify it under the same terms as Perl itself.
908              
909              
910             =head1 DISCLAIMER OF WARRANTY
911              
912             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
913             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
914             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
915             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
916             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
917             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
918             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
919             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
920             NECESSARY SERVICING, REPAIR, OR CORRECTION.
921              
922             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
923             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
924             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
925             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
926             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
927             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
928             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
929             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
930             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
931             SUCH DAMAGES.