Perl Best Practices [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Perl Best Practices [Electronic resources] - نسخه متنی

Damian Conway

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


10.14. Interactivity


Don't reinvent the standard test for interactivity .


The is_interactive( ) subroutine used in the previous guideline is surprisingly difficult to implement. It sounds simple enough: just confirm that both input and output filehandles are connected to the terminal. If the input isn't, there's no need to prompt, as the user won't be entering the data directly. And if the output isn't, there's no need to prompt, because the user wouldn't see the prompt message anyway.

So most people just write:


sub is_interactive {
return -t *ARGV && -t *STDOUT;
}
# and later...
if (is_interactive( )) {
print $PROMPT;
}

Unfortunately, even with the use of *ARGV instead of *STDIN (in accordance with the earlier "Standard Input" guideline), that implementation of is_interactive( ) doesn't work.

For a start, the *ARGV filehandle has the special property that it only opens the files in @ARGV when the filehandle is actually first read. So you can't just use the -t builtin on *ARGV:


-t *ARGV

*ARGV won't be opened until you read from it, and you can't read from it until you know whether to prompt; and to know whether to prompt, you have to check where *ARGV was opened to, but *ARGV won't be opened until you read from it.

Several other magical properties of *ARGV can also prevent simple -t tests on the filehandle from providing the correct answer, even if the input stream

is already open. In order to cope with all the special cases, you have to write:


use Scalar::Util qw( openhandle );
sub is_interactive {

# Not interactive if output is not to terminal...

return 0 if not -t *STDOUT;
# If *ARGV is opened, we're interactive if...

if (openhandle *ARGV) {
# ...it's currently opened to the magic '-' file

return -t *STDIN if $ARGV eq '-';
# ...it's at end-of-file and the next file is the magic '-' file

return @ARGV>0 && $ARGV[0] eq '-' && -t *STDIN if eof *ARGV;
# ...it's directly attached to the terminal

return -t *ARGV;
}
# If *ARGV isn't opened, it will be interactive if *STDIN is attached
# to a terminal and either there are no files specified on the command line
# or if there are one or more files and the first is the magic '-' file

return -t *STDIN && (@ARGV==0 || $ARGV[0] eq '-');
}

That is not something you want to have to (re)write yourself for each interactive program you create. Nor something you're ever going to want to maintain yourself. Fortunately, it's already written for you and available from the CPAN, in the IO::Interactive module. Instead of the horrendous subroutine definition shown earlier, you can just write:


use IO::Interactive qw( is_interactive );


# and later...

if (is_interactive( )) {
print $PROMPT;
}

Alternatively, you could use the module's interactive( ) subroutine, which provides a special filehandle that sends output to *STDOUT only if the terminal is interactive (and just discards it otherwise):


use IO::Interactive qw( interactive );

# and later...

print {interactive} $PROMPT;

/ 317