[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 package Term::UI; 2 3 use Carp; 4 use Params::Check qw[check allow]; 5 use Term::ReadLine; 6 use Locale::Maketext::Simple Style => 'gettext'; 7 use Term::UI::History; 8 9 use strict; 10 11 BEGIN { 12 use vars qw[$VERSION $AUTOREPLY $VERBOSE $INVALID]; 13 $VERBOSE = 1; 14 $VERSION = '0.18'; 15 $INVALID = loc('Invalid selection, please try again: '); 16 } 17 18 push @Term::ReadLine::Stub::ISA, __PACKAGE__ 19 unless grep { $_ eq __PACKAGE__ } @Term::ReadLine::Stub::ISA; 20 21 22 =pod 23 24 =head1 NAME 25 26 Term::UI - Term::ReadLine UI made easy 27 28 =head1 SYNOPSIS 29 30 use Term::UI; 31 use Term::ReadLine; 32 33 my $term = Term::ReadLine->new('brand'); 34 35 my $reply = $term->get_reply( 36 prompt => 'What is your favourite colour?', 37 choices => [qw|blue red green|], 38 default => blue, 39 ); 40 41 my $bool = $term->ask_yn( 42 prompt => 'Do you like cookies?', 43 default => 'y', 44 ); 45 46 47 my $string = q[some_command -option --no-foo --quux='this thing']; 48 49 my ($options,$munged_input) = $term->parse_options($string); 50 51 52 ### don't have Term::UI issue warnings -- default is '1' 53 $Term::UI::VERBOSE = 0; 54 55 ### always pick the default (good for non-interactive terms) 56 ### -- default is '0' 57 $Term::UI::AUTOREPLY = 1; 58 59 ### Retrieve the entire session as a printable string: 60 $hist = Term::UI::History->history_as_string; 61 $hist = $term->history_as_string; 62 63 =head1 DESCRIPTION 64 65 C<Term::UI> is a transparent way of eliminating the overhead of having 66 to format a question and then validate the reply, informing the user 67 if the answer was not proper and re-issuing the question. 68 69 Simply give it the question you want to ask, optionally with choices 70 the user can pick from and a default and C<Term::UI> will DWYM. 71 72 For asking a yes or no question, there's even a shortcut. 73 74 =head1 HOW IT WORKS 75 76 C<Term::UI> places itself at the back of the C<Term::ReadLine> 77 C<@ISA> array, so you can call its functions through your term object. 78 79 C<Term::UI> uses C<Term::UI::History> to record all interactions 80 with the commandline. You can retrieve this history, or alter 81 the filehandle the interaction is printed to. See the 82 C<Term::UI::History> manpage or the C<SYNOPSIS> for details. 83 84 =head1 METHODS 85 86 =head2 $reply = $term->get_reply( prompt => 'question?', [choices => \@list, default => $list[0], multi => BOOL, print_me => "extra text to print & record", allow => $ref] ); 87 88 C<get_reply> asks a user a question, and then returns the reply to the 89 caller. If the answer is invalid (more on that below), the question will 90 be reposed, until a satisfactory answer has been entered. 91 92 You have the option of providing a list of choices the user can pick from 93 using the C<choices> argument. If the answer is not in the list of choices 94 presented, the question will be reposed. 95 96 If you provide a C<default> answer, this will be returned when either 97 C<$AUTOREPLY> is set to true, (see the C<GLOBAL VARIABLES> section further 98 below), or when the user just hits C<enter>. 99 100 You can indicate that the user is allowed to enter multiple answers by 101 toggling the C<multi> flag. Note that a list of answers will then be 102 returned to you, rather than a simple string. 103 104 By specifying an C<allow> hander, you can yourself validate the answer 105 a user gives. This can be any of the types that the Params::Check C<allow> 106 function allows, so please refer to that manpage for details. 107 108 Finally, you have the option of adding a C<print_me> argument, which is 109 simply printed before the prompt. It's printed to the same file handle 110 as the rest of the questions, so you can use this to keep track of a 111 full session of Q&A with the user, and retrieve it later using the 112 C<< Term::UI->history_as_string >> function. 113 114 See the C<EXAMPLES> section for samples of how to use this function. 115 116 =cut 117 118 sub get_reply { 119 my $term = shift; 120 my %hash = @_; 121 122 my $tmpl = { 123 default => { default => undef, strict_type => 1 }, 124 prompt => { default => '', strict_type => 1, required => 1 }, 125 choices => { default => [], strict_type => 1 }, 126 multi => { default => 0, allow => [0, 1] }, 127 allow => { default => qr/.*/ }, 128 print_me => { default => '', strict_type => 1 }, 129 }; 130 131 my $args = check( $tmpl, \%hash, $VERBOSE ) 132 or ( carp( loc(q[Could not parse arguments]) ), return ); 133 134 135 ### add this to the prompt to indicate the default 136 ### answer to the question if there is one. 137 my $prompt_add; 138 139 ### if you supplied several choices to pick from, 140 ### we'll print them seperately before the prompt 141 if( @{$args->{choices}} ) { 142 my $i; 143 144 for my $choice ( @{$args->{choices}} ) { 145 $i++; # the answer counter -- but humans start counting 146 # at 1 :D 147 148 ### so this choice is the default? add it to 'prompt_add' 149 ### so we can construct a "foo? [DIGIT]" type prompt 150 $prompt_add = $i if $choice eq $args->{default}; 151 152 ### create a "DIGIT> choice" type line 153 $args->{print_me} .= sprintf "\n%3s> %-s", $i, $choice; 154 } 155 156 ### we listed some choices -- add another newline for 157 ### pretty printing 158 $args->{print_me} .= "\n" if $i; 159 160 ### allowable answers are now equal to the choices listed 161 $args->{allow} = $args->{choices}; 162 163 ### no choices, but a default? set 'prompt_add' to the default 164 ### to construct a 'foo? [DEFAULT]' type prompt 165 } elsif ( defined $args->{default} ) { 166 $prompt_add = $args->{default}; 167 } 168 169 ### we set up the defaults, prompts etc, dispatch to the readline call 170 return $term->_tt_readline( %$args, prompt_add => $prompt_add ); 171 172 } 173 174 =head2 $bool = $term->ask_yn( prompt => "your question", [default => (y|1,n|0), print_me => "extra text to print & record"] ) 175 176 Asks a simple C<yes> or C<no> question to the user, returning a boolean 177 indicating C<true> or C<false> to the caller. 178 179 The C<default> answer will automatically returned, if the user hits 180 C<enter> or if C<$AUTOREPLY> is set to true. See the C<GLOBAL VARIABLES> 181 section further below. 182 183 Also, you have the option of adding a C<print_me> argument, which is 184 simply printed before the prompt. It's printed to the same file handle 185 as the rest of the questions, so you can use this to keep track of a 186 full session of Q&A with the user, and retrieve it later using the 187 C<< Term::UI->history_as_string >> function. 188 189 190 See the C<EXAMPLES> section for samples of how to use this function. 191 192 =cut 193 194 sub ask_yn { 195 my $term = shift; 196 my %hash = @_; 197 198 my $tmpl = { 199 default => { default => undef, allow => [qw|0 1 y n|], 200 strict_type => 1 }, 201 prompt => { default => '', required => 1, strict_type => 1 }, 202 print_me => { default => '', strict_type => 1 }, 203 multi => { default => 0, no_override => 1 }, 204 choices => { default => [qw|y n|], no_override => 1 }, 205 allow => { default => [qr/^y(?:es)?$/i, qr/^n(?:o)?$/i], 206 no_override => 1 207 }, 208 }; 209 210 my $args = check( $tmpl, \%hash, $VERBOSE ) or return undef; 211 212 ### uppercase the default choice, if there is one, to be added 213 ### to the prompt in a 'foo? [Y/n]' type style. 214 my $prompt_add; 215 { my @list = @{$args->{choices}}; 216 if( defined $args->{default} ) { 217 218 ### if you supplied the default as a boolean, rather than y/n 219 ### transform it to a y/n now 220 $args->{default} = $args->{default} =~ /\d/ 221 ? { 0 => 'n', 1 => 'y' }->{ $args->{default} } 222 : $args->{default}; 223 224 @list = map { lc $args->{default} eq lc $_ 225 ? uc $args->{default} 226 : $_ 227 } @list; 228 } 229 230 $prompt_add .= join("/", @list); 231 } 232 233 my $rv = $term->_tt_readline( %$args, prompt_add => $prompt_add ); 234 235 return $rv =~ /^y/i ? 1 : 0; 236 } 237 238 239 240 sub _tt_readline { 241 my $term = shift; 242 my %hash = @_; 243 244 local $Params::Check::VERBOSE = 0; # why is this? 245 local $| = 1; # print ASAP 246 247 248 my ($default, $prompt, $choices, $multi, $allow, $prompt_add, $print_me); 249 my $tmpl = { 250 default => { default => undef, strict_type => 1, 251 store => \$default }, 252 prompt => { default => '', strict_type => 1, required => 1, 253 store => \$prompt }, 254 choices => { default => [], strict_type => 1, 255 store => \$choices }, 256 multi => { default => 0, allow => [0, 1], store => \$multi }, 257 allow => { default => qr/.*/, store => \$allow, }, 258 prompt_add => { default => '', store => \$prompt_add }, 259 print_me => { default => '', store => \$print_me }, 260 }; 261 262 check( $tmpl, \%hash, $VERBOSE ) or return; 263 264 ### prompts for Term::ReadLine can't be longer than one line, or 265 ### it can display wonky on some terminals. 266 history( $print_me ) if $print_me; 267 268 269 ### we might have to add a default value to the prompt, to 270 ### show the user what will be picked by default: 271 $prompt .= " [$prompt_add]: " if $prompt_add; 272 273 274 ### are we in autoreply mode? 275 if ($AUTOREPLY) { 276 277 ### you used autoreply, but didnt provide a default! 278 carp loc( 279 q[You have '%1' set to true, but did not provide a default!], 280 '$AUTOREPLY' 281 ) if( !defined $default && $VERBOSE); 282 283 ### print it out for visual feedback 284 history( join ' ', grep { defined } $prompt, $default ); 285 286 ### and return the default 287 return $default; 288 } 289 290 291 ### so, no AUTOREPLY, let's see what the user will answer 292 LOOP: { 293 294 ### annoying bug in T::R::Perl that mucks up lines with a \n 295 ### in them; So split by \n, save the last line as the prompt 296 ### and just print the rest 297 { my @lines = split "\n", $prompt; 298 $prompt = pop @lines; 299 300 history( "$_\n" ) for @lines; 301 } 302 303 ### pose the question 304 my $answer = $term->readline($prompt); 305 $answer = $default unless length $answer; 306 307 $term->addhistory( $answer ) if length $answer; 308 309 ### add both prompt and answer to the history 310 history( "$prompt $answer", 0 ); 311 312 ### if we're allowed to give multiple answers, split 313 ### the answer on whitespace 314 my @answers = $multi ? split(/\s+/, $answer) : $answer; 315 316 ### the return value list 317 my @rv; 318 319 if( @$choices ) { 320 321 for my $answer (@answers) { 322 323 ### a digit implies a multiple choice question, 324 ### a non-digit is an open answer 325 if( $answer =~ /\D/ ) { 326 push @rv, $answer if allow( $answer, $allow ); 327 } else { 328 329 ### remember, the answer digits are +1 compared to 330 ### the choices, because humans want to start counting 331 ### at 1, not at 0 332 push @rv, $choices->[ $answer - 1 ] 333 if $answer > 0 && defined $choices->[ $answer - 1]; 334 } 335 } 336 337 ### no fixed list of choices.. just check if the answers 338 ### (or otherwise the default!) pass the allow handler 339 } else { 340 push @rv, grep { allow( $_, $allow ) } 341 scalar @answers ? @answers : ($default); 342 } 343 344 ### if not all the answers made it to the return value list, 345 ### at least one of them was an invalid answer -- make the 346 ### user do it again 347 if( (@rv != @answers) or 348 (scalar(@$choices) and not scalar(@answers)) 349 ) { 350 $prompt = $INVALID; 351 $prompt .= "[$prompt_add] " if $prompt_add; 352 redo LOOP; 353 354 ### otherwise just return the answer, or answers, depending 355 ### on the multi setting 356 } else { 357 return $multi ? @rv : $rv[0]; 358 } 359 } 360 } 361 362 =head2 ($opts, $munged) = $term->parse_options( STRING ); 363 364 C<parse_options> will convert all options given from an input string 365 to a hash reference. If called in list context it will also return 366 the part of the input string that it found no options in. 367 368 Consider this example: 369 370 my $str = q[command --no-foo --baz --bar=0 --quux=bleh ] . 371 q[--option="some'thing" -one-dash -single=blah' arg]; 372 373 my ($options,$munged) = $term->parse_options($str); 374 375 ### $options would contain: ### 376 $options = { 377 'foo' => 0, 378 'bar' => 0, 379 'one-dash' => 1, 380 'baz' => 1, 381 'quux' => 'bleh', 382 'single' => 'blah\'', 383 'option' => 'some\'thing' 384 }; 385 386 ### and this is the munged version of the input string, 387 ### ie what's left of the input minus the options 388 $munged = 'command arg'; 389 390 As you can see, you can either use a single or a double C<-> to 391 indicate an option. 392 If you prefix an option with C<no-> and do not give it a value, it 393 will be set to 0. 394 If it has no prefix and no value, it will be set to 1. 395 Otherwise, it will be set to its value. Note also that it can deal 396 fine with single/double quoting issues. 397 398 =cut 399 400 sub parse_options { 401 my $term = shift; 402 my $input = shift; 403 404 my $return = {}; 405 406 ### there's probably a more elegant way to do this... ### 407 while ( $input =~ s/(?:^|\s+)--?([-\w]+=("|').+?\2)(?=\Z|\s+)// or 408 $input =~ s/(?:^|\s+)--?([-\w]+=\S+)(?=\Z|\s+)// or 409 $input =~ s/(?:^|\s+)--?([-\w]+)(?=\Z|\s+)// 410 ) { 411 my $match = $1; 412 413 if( $match =~ /^([-\w]+)=("|')(.+?)\2$/ ) { 414 $return->{$1} = $3; 415 416 } elsif( $match =~ /^([-\w]+)=(\S+)$/ ) { 417 $return->{$1} = $2; 418 419 } elsif( $match =~ /^no-?([-\w]+)$/i ) { 420 $return->{$1} = 0; 421 422 } elsif ( $match =~ /^([-\w]+)$/ ) { 423 $return->{$1} = 1; 424 425 } else { 426 carp(loc(q[I do not understand option "%1"\n], $match)) if $VERBOSE; 427 } 428 } 429 430 return wantarray ? ($return,$input) : $return; 431 } 432 433 =head2 $str = $term->history_as_string 434 435 Convenience wrapper around C<< Term::UI::History->history_as_string >>. 436 437 Consult the C<Term::UI::History> man page for details. 438 439 =cut 440 441 sub history_as_string { return Term::UI::History->history_as_string }; 442 443 1; 444 445 =head1 GLOBAL VARIABLES 446 447 The behaviour of Term::UI can be altered by changing the following 448 global variables: 449 450 =head2 $Term::UI::VERBOSE 451 452 This controls whether Term::UI will issue warnings and explanations 453 as to why certain things may have failed. If you set it to 0, 454 Term::UI will not output any warnings. 455 The default is 1; 456 457 =head2 $Term::UI::AUTOREPLY 458 459 This will make every question be answered by the default, and warn if 460 there was no default provided. This is particularly useful if your 461 program is run in non-interactive mode. 462 The default is 0; 463 464 =head2 $Term::UI::INVALID 465 466 This holds the string that will be printed when the user makes an 467 invalid choice. 468 You can override this string from your program if you, for example, 469 wish to do localization. 470 The default is C<Invalid selection, please try again: > 471 472 =head2 $Term::UI::History::HISTORY_FH 473 474 This is the filehandle all the print statements from this module 475 are being sent to. Please consult the C<Term::UI::History> manpage 476 for details. 477 478 This defaults to C<*STDOUT>. 479 480 =head1 EXAMPLES 481 482 =head2 Basic get_reply sample 483 484 ### ask a user (with an open question) for their favourite colour 485 $reply = $term->get_reply( prompt => 'Your favourite colour? ); 486 487 which would look like: 488 489 Your favourite colour? 490 491 and C<$reply> would hold the text the user typed. 492 493 =head2 get_reply with choices 494 495 ### now provide a list of choices, so the user has to pick one 496 $reply = $term->get_reply( 497 prompt => 'Your favourite colour?', 498 choices => [qw|red green blue|] ); 499 500 which would look like: 501 502 1> red 503 2> green 504 3> blue 505 506 Your favourite colour? 507 508 C<$reply> will hold one of the choices presented. C<Term::UI> will repose 509 the question if the user attempts to enter an answer that's not in the 510 list of choices. The string presented is held in the C<$Term::UI::INVALID> 511 variable (see the C<GLOBAL VARIABLES> section for details. 512 513 =head2 get_reply with choices and default 514 515 ### provide a sensible default option -- everyone loves blue! 516 $reply = $term->get_reply( 517 prompt => 'Your favourite colour?', 518 choices => [qw|red green blue|], 519 default => 'blue' ); 520 521 which would look like: 522 523 1> red 524 2> green 525 3> blue 526 527 Your favourite colour? [3]: 528 529 Note the default answer after the prompt. A user can now just hit C<enter> 530 (or set C<$Term::UI::AUTOREPLY> -- see the C<GLOBAL VARIABLES> section) and 531 the sensible answer 'blue' will be returned. 532 533 =head2 get_reply using print_me & multi 534 535 ### allow the user to pick more than one colour and add an 536 ### introduction text 537 @reply = $term->get_reply( 538 print_me => 'Tell us what colours you like', 539 prompt => 'Your favourite colours?', 540 choices => [qw|red green blue|], 541 multi => 1 ); 542 543 which would look like: 544 545 Tell us what colours you like 546 1> red 547 2> green 548 3> blue 549 550 Your favourite colours? 551 552 An answer of C<3 2 1> would fill C<@reply> with C<blue green red> 553 554 =head2 get_reply & allow 555 556 ### pose an open question, but do a custom verification on 557 ### the answer, which will only exit the question loop, if 558 ### the answer matches the allow handler. 559 $reply = $term->get_reply( 560 prompt => "What is the magic number?", 561 allow => 42 ); 562 563 Unless the user now enters C<42>, the question will be reposed over 564 and over again. You can use more sophisticated C<allow> handlers (even 565 subroutines can be used). The C<allow> handler is implemented using 566 C<Params::Check>'s C<allow> function. Check its manpage for details. 567 568 =head2 an elaborate ask_yn sample 569 570 ### ask a user if he likes cookies. Default to a sensible 'yes' 571 ### and inform him first what cookies are. 572 $bool = $term->ask_yn( prompt => 'Do you like cookies?', 573 default => 'y', 574 print_me => 'Cookies are LOVELY!!!' ); 575 576 would print: 577 578 Cookies are LOVELY!!! 579 Do you like cookies? [Y/n]: 580 581 If a user then simply hits C<enter>, agreeing with the default, 582 C<$bool> would be set to C<true>. (Simply hitting 'y' would also 583 return C<true>. Hitting 'n' would return C<false>) 584 585 We could later retrieve this interaction by printing out the Q&A 586 history as follows: 587 588 print $term->history_as_string; 589 590 which would then print: 591 592 Cookies are LOVELY!!! 593 Do you like cookies? [Y/n]: y 594 595 There's a chance we're doing this non-interactively, because a console 596 is missing, the user indicated he just wanted the defaults, etc. 597 598 In this case, simply setting C<$Term::UI::AUTOREPLY> to true, will 599 return from every question with the default answer set for the question. 600 Do note that if C<AUTOREPLY> is true, and no default is set, C<Term::UI> 601 will warn about this and return C<undef>. 602 603 =head1 See Also 604 605 C<Params::Check>, C<Term::ReadLine>, C<Term::UI::History> 606 607 =head1 BUG REPORTS 608 609 Please report bugs or other issues to E<lt>bug-term-ui@rt.cpan.org<gt>. 610 611 =head1 AUTHOR 612 613 This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. 614 615 =head1 COPYRIGHT 616 617 This library is free software; you may redistribute and/or modify it 618 under the same terms as Perl itself. 619 620 =cut
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 17 22:47:18 2015 | Cross-referenced by PHPXref 0.7.1 |