Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Restrict encoding of std streams to lexical scope

by nbtrap (Sexton)
on Aug 09, 2013 at 11:56 UTC ( #1048755=perlquestion: print w/ replies, xml ) Need Help??
nbtrap has asked for the wisdom of the Perl Monks concerning the following question:

I'm looking for a way to encode the standard streams only within one module (file) of a multiple-file package. The "open" pragma works lexically for calls to "open" within a lexical scope, but the "use open ':std', ':encoding(UTF-8)'" declaration has a program-wide effect. For example, the following code doesn't complain:

use warnings; use v5.10; use utf8; my $utf8 = "\x{3bc}\x{1fc6}\x{3bd}\x{3b9}\x{3bd}"; say $utf8; { use open qw(:std :encoding(UTF-8)); say $utf8; }

because a UTF-8 layer is added to STDOUT, STDERR, etc., at compile time and therefore affects the "say $utf8" statement that's outside the lexical scope of the "use open".

Is there any way to restrict the encoding of standard streams to a lexical scope? I don't want to have to say "print $my_fh '...'" every time, and "local *STDOUT", etc., works on dynamic scopes, not lexical scopes.

Comment on Restrict encoding of std streams to lexical scope
Download Code
Re: Restrict encoding of std streams to lexical scope
by choroba (Abbot) on Aug 09, 2013 at 12:33 UTC
    Good question. The only solution I was able to think of uses the "dup" of the handles and a callback. You can add the & prototype to save yourself from typing (sub  ) every time.
    #!/usr/bin/perl use warnings; use strict; use feature 'say'; sub encoding { my $code = shift; open my $STORE_STDOUT, '>&STDOUT' or die $!; binmode STDOUT, 'encoding(UTF-8)'; $code->(); open STDOUT, '>&', $STORE_STDOUT or die $!; } my $utf8 = "\x{3bc}\x{1fc6}\x{3bd}\x{3b9}\x{3bd}"; say 'A:', $utf8; encoding(sub { # Here, no warning is issued. say 'B:', $utf8; }); # End of scope, STDOUT is no longer affected. say 'C:', $utf8;
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Restrict encoding of std streams to lexical scope
by Perlbotics (Abbot) on Aug 09, 2013 at 12:43 UTC

    I fiddled around with require and open::import(...) but that didn't made things better. Since, you want a lexical-region where STDOUT has UTF-properties, you could emulate that with a prototyped helper function that employed binmode and local to temporarily change STDOUT's behaviour:

    use warnings; use v5.10; use utf8; #-- prototype to setup a block where STDOUT is UTF-8 sub with_utf(&) { open(my $stdout, ">&STDOUT"); #-- STDERR analogue local *STDOUT = $stdout; binmode(*STDOUT, ':encoding(UTF-8)'); shift->(); } my $utf8 = "\x{3bc}\x{1fc6}\x{3bd}\x{3b9}\x{3bd}"; say "Default: $utf8"; # Wide character in say at 1048755.pl line 16 +. with_utf { say "Lexical: $utf8"; # (no warning) }; say "Default: $utf8"; # Wide character in say at 1048755.pl line 22 +.

    Result:

    linux> perl 1048755.pl
    Wide character in say at 1048755.pl line 16.
    Default: μῆνιν
    Lexical: μῆνιν
    Wide character in say at 1048755.pl line 22.
    Default: μῆνιν

    Seems, choroba had the same idea... ;-)

      I even played with require and import in the beginning, as well, to no avail :-)
      لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Restrict encoding of std streams to lexical scope
by vsespb (Hermit) on Aug 13, 2013 at 08:28 UTC
    You can write your own wrapper for print() and use %^H (see perlvar) to control behaviour in lexical scopes.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1048755]
Approved by choroba
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (12)
As of 2014-07-28 15:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (201 votes), past polls