diff options
author | Salvatore Bonaccorso <carnil@debian.org> | 2015-03-08 18:16:22 +0100 |
---|---|---|
committer | Salvatore Bonaccorso <carnil@debian.org> | 2015-03-08 18:16:22 +0100 |
commit | fbb6fc10e789774716ad12a77ff2912dc63d8077 (patch) | |
tree | 45a84f5fd0766d74b0788275921a5ed29ffb06b5 | |
parent | 0e2232849fa44740288cc201f645e71b89f5a89c (diff) | |
parent | 53511b12a15cc50e60a960f9a450316a72368228 (diff) |
Merge tag 'upstream/0.004012'
Upstream version 0.004012
-rw-r--r-- | Changes | 18 | ||||
-rw-r--r-- | MANIFEST | 4 | ||||
-rw-r--r-- | META.json | 42 | ||||
-rw-r--r-- | META.yml | 40 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | lib/IO/Prompter.pm | 102 | ||||
-rw-r--r-- | t/autoexport.t | 27 | ||||
-rw-r--r-- | t/errors.t | 15 |
8 files changed, 205 insertions, 45 deletions
@@ -150,5 +150,19 @@ Revision history for IO-Prompter * Added 'normal', 'default', 'standard', etc. to colour translation - * Added <CTRL-F> at start of faked input to defer next fake and insert real input - (i.e. like <ESC> but doesn't throw away the line that was scheduled next) + * Added <ESC><ESC> at start of faked input to defer next fake and insert real input + (i.e. like <ESC>, but doesn't throw away the line that was scheduled next) + + +0.004012 Wed Feb 4 09:46:17 2015 + + * Added -void option to silence void warnings + + * Added ability to declare lexically scoped wrapper subs + (thanks Schwern!) + + * Documented incompatibility with Moose + (thanks Torbjørn!) + + * Handle terminal escape sequences (e.g. arrow keys) more gracefully + (Thanks, Lukasz!) @@ -40,4 +40,6 @@ t/orlast.t t/styles.t t/lexical_options.t t/list_context.t -META.yml Module meta-data (added by MakeMaker) +t/autoexport.t +META.yml Module YAML meta-data (added by MakeMaker) +META.json Module JSON meta-data (added by MakeMaker) diff --git a/META.json b/META.json new file mode 100644 index 0000000..3a74c81 --- /dev/null +++ b/META.json @@ -0,0 +1,42 @@ +{ + "abstract" : "Prompt for input, read it, clean it, return it.", + "author" : [ + "Damian Conway <DCONWAY@CPAN.org>" + ], + "dynamic_config" : 1, + "generated_by" : "ExtUtils::MakeMaker version 7.02, CPAN::Meta::Converter version 2.142690", + "license" : [ + "perl_5" + ], + "meta-spec" : { + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", + "version" : "2" + }, + "name" : "IO-Prompter", + "no_index" : { + "directory" : [ + "t", + "inc" + ] + }, + "prereqs" : { + "build" : { + "requires" : { + "ExtUtils::MakeMaker" : "0" + } + }, + "configure" : { + "requires" : { + "ExtUtils::MakeMaker" : "0" + } + }, + "runtime" : { + "requires" : { + "Contextual::Return" : "0", + "Test::More" : "0" + } + } + }, + "release_status" : "stable", + "version" : "0.004012" +} @@ -1,23 +1,23 @@ ---- #YAML:1.0 -name: IO-Prompter -version: 0.004011 -abstract: Prompt for input, read it, clean it, return it. +--- +abstract: 'Prompt for input, read it, clean it, return it.' author: - - Damian Conway <DCONWAY@CPAN.org> -license: perl -distribution_type: module -configure_requires: - ExtUtils::MakeMaker: 0 + - 'Damian Conway <DCONWAY@CPAN.org>' build_requires: - ExtUtils::MakeMaker: 0 -requires: - Contextual::Return: 0 - Test::More: 0 -no_index: - directory: - - t - - inc -generated_by: ExtUtils::MakeMaker version 6.57_05 + ExtUtils::MakeMaker: '0' +configure_requires: + ExtUtils::MakeMaker: '0' +dynamic_config: 1 +generated_by: 'ExtUtils::MakeMaker version 7.02, CPAN::Meta::Converter version 2.142690' +license: perl meta-spec: - url: http://module-build.sourceforge.net/META-spec-v1.4.html - version: 1.4 + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: '1.4' +name: IO-Prompter +no_index: + directory: + - t + - inc +requires: + Contextual::Return: '0' + Test::More: '0' +version: '0.004012' @@ -1,4 +1,4 @@ -IO::Prompter version 0.004011 +IO::Prompter version 0.004012 Prompt for, read, vet, chomp, and encapsulate input. Like so: diff --git a/lib/IO/Prompter.pm b/lib/IO/Prompter.pm index a96600f..96987fc 100644 --- a/lib/IO/Prompter.pm +++ b/lib/IO/Prompter.pm @@ -9,7 +9,7 @@ use Contextual::Return qw< PUREBOOL BOOL SCALAR METHOD VOID LIST RETOBJ >; use Scalar::Util qw< openhandle looks_like_number >; use Symbol qw< qualify_to_ref >; -our $VERSION = '0.004011'; +our $VERSION = '0.004012'; my $fake_input; # Flag that we're faking input from the source @@ -74,8 +74,9 @@ my @YESNO_PROMPTS = ( # Remember returned values for history completion... my %history_cache; -# Track lexically-scoped default options... -my @lexical_options = []; +# Track lexically-scoped default options and wrapper subs... +my @lexical_options = []; +my @lexical_wrappers = []; # Export the prompt() sub... sub import { @@ -92,6 +93,22 @@ sub import { $^H{'IO::Prompter::scope_number'} = $#lexical_options; } + # Handle lexical wrappers... + elsif (ref $config_data eq 'HASH') { + push @lexical_options, []; + $lexical_wrappers[ $#lexical_options ] = $config_data; + $^H{'IO::Prompter::scope_number'} = $#lexical_options; + for my $subname (keys %{$config_data}) { + my @args = @{$config_data->{$subname}}; + no strict 'refs'; + no warnings 'redefine'; + *{caller().'::'.$subname} = sub { + my $scope_number = (caller 0)[10]{'IO::Prompter::scope_number'}; + return prompt(@{$lexical_wrappers[$scope_number]{$subname}//[]}, @_); + }; + } + } + # Handler faked input specifications... elsif (defined $config_data) { $fake_input = $config_data; @@ -103,9 +120,6 @@ sub import { # Prompt for, read, vet, and return input... sub prompt { - _warn( void => 'Useless use of prompt() in void context' ) - if VOID; - # Reclaim full control of print statements while prompting... local $\ = ''; @@ -116,6 +130,9 @@ sub prompt { # Extract and sanitize configuration arguments... my $opt_ref = _decode_args(@{$lexical_options[$scope_num]}, @_); + _warn( void => 'Useless use of prompt() in void context' ) + if VOID && !$opt_ref->{-void}; + # Set up yesno prompts if required... my @yesno_prompts = ($opt_ref->{-yesno}{count}//0) > 1 ? @YESNO_PROMPTS : (); @@ -573,6 +590,9 @@ sub _decode_args { when (/^-i/) { $option{-integer} = 1; $redo = 1; } when (/^-n/) { $option{-number} = 1; $redo = 1; } + # Specify void context is okay... + when (/^-void$/) { $option{-void} = 1; } + # Specify verbatim return value... when (/^-verb(?:atim)?$/) { $option{-verbatim} = 1; } when (/^-v/) { $option{-verbatim} = 1; $redo = 1;} @@ -1669,7 +1689,7 @@ sub _std_printer_to { return sub { my $style = shift; my @loc = (@_); - s{\e}{}gxms for @loc; + s{\e}{^}gxms for @loc; print {$out_filehandle} _stylize($opt_ref->{$style}(@loc), @loc); }; } @@ -1677,7 +1697,7 @@ sub _std_printer_to { return sub { shift; # ...ignore style my @loc = (@_); - s{\e}{}gxms for @loc; + s{\e}{^}gxms for @loc; print {$out_filehandle} @loc; }; } @@ -1698,7 +1718,7 @@ IO::Prompter - Prompt for input, read it, clean it, return it. =head1 VERSION -This document describes IO::Prompter version 0.004011 +This document describes IO::Prompter version 0.004012 =head1 SYNOPSIS @@ -1855,6 +1875,8 @@ or add a L<"no-op"|"Escaping otherwise magic options"> to them. -v -verb[atim] Return the input string (no context sensitivity) + -void Don't complain in void context + * -w -wipe Clear screen -wipefirst Clear screen on first prompt() call only @@ -1901,6 +1923,43 @@ scope, use: use IO::Prompter []; +=head2 Prebound options + +You can also ask IO::Prompter to export modified versions of C<prompt()> +with zero or more options prebound. For example, you can request an +C<ask()> subroutine that acts exactly like C<prompt()> but has the C<- +yn> option pre-specified, or a C<pause()> subroutine that is C<prompt()> +with a "canned" prompt and the C<-echo>, C<-single>, and C<-void> options. + +To specify such subroutines, pass a single hash reference when +loading the module: + + use IO::Prompter { + ask => [-yn], + pause => [-prompt=>'(Press any key to continue)', -echo, -single, -void], + } + +Each key will be used as the name of a separate subroutine to be +exported, and each value must be an array reference, containing the +arguments that are to be automatically supplied. + +The resulting subroutines are simply lexically scoped wrappers around +C<prompt()>, with the specified arguments prepended to the normal +argument list, equivalent to something like: + + my sub ask { + return prompt(-yn, @_); + } + + my sub pause { + return prompt(-prompt=>'(Press any key to continue)', -echo, -single, -void, @_); + } + +Note that these subroutines are lexically scoped, so if you want to use +them throughtout a source file, they should be declared in the outermost +scope of your program. + + =head2 Options reference =head3 Specifying what to prompt @@ -3215,18 +3274,11 @@ Here, we're using prompt simply to pause the application after the data is printed. It doesn't matter what the user types in; the typing itself is the message (and the message is "move along"). -In such cases, the "useless use..." warning can be suppressed either by -explicitly turning off the warning: - - say $data; - no warnings 'void'; - prompt('END OF DATA. Press any key to exit', -echo, -single); - exit; - -or by removing the void context itself with: +In such cases, the "useless use..." warning can be suppressed using the +C<< -void >> option: say $data; - scalar prompt('END OF DATA. Press any key to exit', -echo, -single); + prompt('END OF DATA. Press any key to exit', -echo, -single, -void); exit; @@ -3458,7 +3510,17 @@ The module also works much better if Term::ReadKey is available =head1 INCOMPATIBILITIES -None reported. +This module does not play well with Moose (or more specifically, with +Moose::Exporter) because both of them try to play sneaky games with +Scalar::Util::blessed. + +The current solution is to make sure that you load Moose before +loading IO::Prompter. Even just doing this: + + use Moose (); + use IO::Prompter; + +is sufficient. =head1 BUGS AND LIMITATIONS diff --git a/t/autoexport.t b/t/autoexport.t new file mode 100644 index 0000000..aa44b9d --- /dev/null +++ b/t/autoexport.t @@ -0,0 +1,27 @@ +use Test::More; + +use IO::Prompter { ask => [-yn1, -verbatim] }; + +{ + open my $in_fh, '<', \'y' or die; + my $response = ask(-in=>$in_fh); + is $response, 'y' => 'Ask matched on single y'; + ok !ref($response) => 'Verbatim'; +} + +{ + use IO::Prompter { ask => [-yn1] }; + open my $in_fh, '<', \'y' or die; + my $response = ask(-in=>$in_fh); + is $response, 'y' => 'Ask matched on single y'; + ok ref($response) => 'Not verbatim'; +} + +{ + open my $in_fh, '<', \'y' or die; + my $response = ask(-in=>$in_fh); + is $response, 'y' => 'Ask matched on single y'; + ok !ref($response) => 'Verbatim'; +} + +done_testing(); @@ -1,4 +1,4 @@ -use 5.010; +#use 5.010; use warnings; use Test::More 'no_plan'; @@ -28,6 +28,7 @@ like $@, qr/prompt\(\): Invalid value for -timeout \(expected number of seconds\ fail 'void context warning' if !$warned; } + { no warnings 'void'; my $warned; @@ -44,6 +45,18 @@ like $@, qr/prompt\(\): Invalid value for -timeout \(expected number of seconds\ { my $warned; local $SIG{__WARN__} = sub { + $warned = 1; + }; + + my $input = 'text'; + open my $fh, '<', \$input or die $!; + prompt "Enter line 1", -in=>$fh, -void; + ok !$warned => 'turned off void context warning with -void'; +} + +{ + my $warned; + local $SIG{__WARN__} = sub { my ($warning) = @_; like $warning, qr/\Aprompt\(\): Unknown option -zen ignored/ => 'Unknown option warning'; |