File Coverage

blib/lib/open/layers.pm
Criterion Covered Total %
statement 41 42 97.6
branch 22 30 73.3
condition 11 17 64.7
subroutine 6 6 100.0
pod n/a
total 80 95 84.2


line stmt bran cond sub pod time code
1             package open::layers;
2              
3 20     20   1844357 use strict;
  20         237  
  20         580  
4 20     20   100 use warnings;
  20         20  
  20         441  
5 20     20   81 use Carp ();
  20         39  
  20         240  
6 20     20   88 use Scalar::Util ();
  20         41  
  20         13127  
7              
8             our $VERSION = '0.003';
9              
10             # series of layers delimited by colons and consisting of non-space characters
11             # allow spaces before and between layers because core does, but don't require them
12             # we require a leading colon even though core doesn't, because it's expected anyway
13             my $LAYERS_SPEC = qr/\A\s*(?::[^\s:]+\s*)+\z/;
14              
15             sub import {
16 45     45   35643909 my $class = shift;
17 45         62167 while (@_) {
18 28         993 my $arg = shift;
19 28         1034 my $ref = Scalar::Util::reftype $arg;
20 28 100 33     3802 if ((defined $ref and ($ref eq 'GLOB' or $ref eq 'IO'))
    100 66        
    50 66        
      100        
21             or (!defined $ref and Scalar::Util::reftype \$arg eq 'GLOB')) {
22 2 50       7 Carp::croak "open::layers: No layer provided for handle $arg" unless @_;
23 2         4 my $layer = shift;
24 2 50       21 Carp::croak "open::layers: Invalid layer specification $layer" unless $layer =~ m/$LAYERS_SPEC/;
25 2 50       26 binmode $arg, $layer or Carp::croak "open::layers: binmode $arg failed: $!";
26             } elsif ($arg =~ m/\ASTD(IN|OUT|ERR|IO)\z/) {
27 16         723 my $which = $1;
28 16 50       164 Carp::croak "open::layers: No layer provided for handle $arg" unless @_;
29 16         207 my $layer = shift;
30 16 50       983 Carp::croak "open::layers: Invalid layer specification $layer" unless $layer =~ m/$LAYERS_SPEC/;
31 16 100       466 my @handles = $which eq 'IN' ? \*STDIN
    100          
    100          
32             : $which eq 'OUT' ? \*STDOUT
33             : $which eq 'ERR' ? \*STDERR
34             : (\*STDIN, \*STDOUT, \*STDERR);
35 16   33 8   2388 binmode $_, $layer or Carp::croak "open::layers: binmode $_ failed: $!" for @handles;
  8         438  
  8         79  
  8         312  
36             } elsif ($arg =~ m/\A(rw|r|w)\z/) {
37 10         154 my $which = $1;
38 10 50       55 Carp::croak "open::layers: No layer provided for $arg handles" unless @_;
39 10         74 my $layer = shift;
40 10 50       244 Carp::croak "open::layers: Invalid layer specification $layer" unless $layer =~ m/$LAYERS_SPEC/;
41 10         80 my @layers = $layer =~ m/(:[^\s:]+)/g; # split up the layers so we can set ${^OPEN} like open.pm
42 10   100     247 my ($in, $out) = split /\0/, (${^OPEN} || "\0"), -1;
43 10 100       65 if ($which ne 'w') { # r, rw
44 8         28 $in = join ' ', @layers;
45             }
46 10 100       22 if ($which ne 'r') { # w, rw
47 8         16 $out = join ' ', @layers;
48             }
49 10         2789 ${^OPEN} = join "\0", $in, $out;
50             } else {
51 0         0 Carp::croak "open::layers: Unknown flag $arg (expected STD(IN|OUT|ERR|IO), r/w/rw, or filehandle)";
52             }
53             }
54             }
55              
56             1;
57              
58             =head1 NAME
59              
60             open::layers - Set default PerlIO layers
61              
62             =head1 SYNOPSIS
63              
64             {
65             # set default layers for open() in this lexical scope
66             use open::layers r => ':encoding(UTF-8)';
67             }
68             # encoding layer no longer applied to handles opened here
69              
70             use open::layers r => ':encoding(cp1252)', w => ':encoding(UTF-8)';
71             use open::layers rw => ':encoding(UTF-8)'; # all opened handles
72              
73             # push layers on the standard handles (not lexical)
74             use open::layers STDIN => ':encoding(UTF-8)';
75             use open::layers STDOUT => ':encoding(UTF-8)', STDERR => ':encoding(UTF-8)';
76             use open::layers STDIO => ':encoding(UTF-8)'; # shortcut for all of above
77              
78             =head1 DESCRIPTION
79              
80             This pragma is a reimagination of the core L pragma, which either pushes
81             L layers on the global standard handles, or sets default L
82             layers for handles opened in the current lexical scope (meaning, innermost
83             braces or the file scope). The interface is redesigned to be more explicit and
84             intuitive. See L for details.
85              
86             =head1 ARGUMENTS
87              
88             Each operation is specified in a pair of arguments: the flag specifying the
89             target of the operation, and the layer(s) to apply. Multiple layers can be
90             specified like C<:foo:bar>, as in L or
91             L.
92              
93             The flag may be any one of:
94              
95             =over
96              
97             =item STDIN, STDOUT, STDERR, STDIO
98              
99             These strings indicate to push the layer(s) onto the associated standard handle
100             with L, affecting usage of that handle globally,
101             equivalent to calling L on the handle in a C
102             block. C is a shortcut to operate on all three standard handles.
103              
104             Note that this will also affect reading from C via L
105             (empty C<< <> >>, C<<< <<>> >>>, or L).
106              
107             =item $handle
108              
109             An arbitrary filehandle (glob or reference to a glob, B a bareword) will
110             have layer(s) pushed onto it directly, affecting all usage of that handle,
111             similarly to the operation on standard handles.
112              
113             Note that the handle must be opened in the compile phase (such as in a
114             preceding C block) in order to be available for this pragma to operate
115             on it.
116              
117             =item r, w, rw
118              
119             These strings indicate to set the default layer stack for handles opened in the
120             current lexical scope: C for handles opened for reading, C for handles
121             opened for writing (or C), and C for all handles.
122              
123             This lexical effect works by setting L<${^OPEN}|perlvar/${^OPEN}>, like the
124             L pragma and C<-C> switch. The functions L,
125             L, L,
126             L, L,
127             L, and L (C or
128             backticks) are affected by this variable. Indirect calls to these functions via
129             modules like L occur in a different lexical scope, so are not
130             affected, nor are directory handles such as opened by
131             L.
132              
133             Note that this will also affect implicitly opened read handles such as files
134             opened by L (empty C<< <> >>, C<<< <<>> >>>, or
135             L), but B C via C, or
136             L.
137              
138             A three-argument L call that specifies layers will ignore
139             any lexical defaults. A single C<:> (colon) also does this, using the default
140             layers for the architecture.
141              
142             use open::layers rw => ':encoding(UTF-8)';
143             open my $fh, '<', $file; # sets UTF-8 layer (and its implicit platform defaults)
144             open my $fh, '>:unix', $file; # ignores UTF-8 layer and sets :unix
145             open my $fh, '<:', $file; # ignores UTF-8 layer and sets platform defaults
146              
147             =back
148              
149             =head1 COMPARISON TO open.pm
150              
151             =over
152              
153             =item *
154              
155             Unlike L, C requires that the target of the operation is
156             always specified so as to not confuse global and lexical operations.
157              
158             =item *
159              
160             Unlike L, C can push layers to the standard handles without
161             affecting handles opened in the lexical scope.
162              
163             =item *
164              
165             Unlike L, multiple layers are not required to be space separated.
166              
167             =item *
168              
169             Unlike L, duplicate existing encoding layers are not removed from the
170             standard handles. Either ensure that nothing else is setting encoding layers on
171             these handles, or use the C<:raw> pseudo-layer to "reset" the layers to a
172             binary stream before applying text translation layers.
173              
174             use open::layers STDIO => ':raw:encoding(UTF-16BE)';
175             use open::layers STDIO => ':raw:encoding(UTF-16BE):crlf'; # on Windows 5.14+
176              
177             =item *
178              
179             Unlike L, the C<:locale> pseudo-layer is not (yet) implemented. Consider
180             installing L to support this layer.
181              
182             =back
183              
184             =head1 PERLIO LAYERS
185              
186             PerlIO layers are described in detail in the L documentation. Their
187             implementation has several historical quirks that may be useful to know:
188              
189             =over
190              
191             =item *
192              
193             Layers are an ordered stack; a read operation will go through the layers in the
194             order they are set (left to right), and a write operation in the reverse order.
195              
196             =item *
197              
198             The C<:unix> layer implements the lowest level unbuffered I/O, even on Windows.
199             Most other layers operate on top of this and usually a buffering layer like
200             C<:perlio> or C<:crlf>, and these low-level layers make up the platform
201             defaults.
202              
203             =item *
204              
205             Many layers are not real layers that actually implement I/O or translation;
206             these are referred to as pseudo-layers. Some (like C<:utf8>) set flags on
207             previous layers that change how they operate. Some (like C<:pop>) simply modify
208             the existing set of layers. Some (like C<:raw>) may do both.
209              
210             =item *
211              
212             The C<:crlf> layer is not just a translation between C<\n> and C. On
213             Windows, it is the layer that implements I/O buffering (like C<:perlio> on
214             Unix-like systems), and operations that would remove the C translation
215             (like L with no layers, or pushing a C<:raw>
216             pseudo-layer) actually just disable the C translation flag on this layer.
217             Since Perl 5.14, pushing a C<:crlf> layer on top of other translation layers on
218             Windows correctly adds a C translation layer in that position. (On
219             Unix-like systems, C<:crlf> is a mundane C translation layer.)
220              
221             =item *
222              
223             The C<:utf8> pseudo-layer sets a flag that indicates the preceding stack of
224             layers will translate the input to Perl's internal upgraded string format,
225             which may resemble UTF-8 or UTF-EBCDIC, or will translate the output from that
226             format. It is B an encoding translation layer, but an assumption about the
227             byte stream; use C<:encoding(UTF-8)> or L to apply a
228             translation layer. Any encoding translation layer will generally set the
229             C<:utf8> flag, even when the desired encoding is not UTF-8, as they translate
230             between the desired encoding and Perl's internal format. (The C<:bytes>
231             pseudo-layer unsets this flag, which is very dangerous if encoding translation
232             layers are used.)
233              
234             =item *
235              
236             I/O to an in-memory scalar variable instead of a file is implemented by the
237             C<:scalar> layer taking the place of the platform defaults, see
238             L. The scalar is expected to act like a file, i.e. only contain
239             or store bytes.
240              
241             =item *
242              
243             Layers specified when opening a handle, such as in a three-argument
244             L or default layers set in L<${^OPEN}|perlvar/${^OPEN}>
245             (via the lexical usage of this pragma or the L pragma), will define the
246             complete stack of layers on that handle. Certain layers implicitly include
247             lower-level layers that are needed, for example C<:encoding(UTF-8)> will
248             implicitly prepend the platform defaults C<:unix:perlio> (or similar).
249              
250             =item *
251              
252             In contrast, when adjusting layers on an existing handle with
253             L (or the non-lexical usage of this pragma or the
254             L pragma), the specified layers are pushed at the end of the handle's
255             existing layer stack, and any special operations of pseudo-layers take effect.
256             So you can open an unbuffered handle with only C<:unix>, but to remove existing
257             layers on an already open handle, you must push pseudo-layers like C<:pop> or
258             C<:raw> (equivalent to calling L with no layers).
259              
260             =back
261              
262             =head1 CAVEATS
263              
264             The L layers and L pragma have experienced several issues over
265             the years, most of which can't be worked around by this module. It's
266             recommended to use a recent Perl if you will be using complex layers; for
267             compatibility with old Perls, stick to L (either
268             with no layers for a binary stream, or with a single C<:encoding> layer). Here
269             are some selected issues:
270              
271             =over
272              
273             =item *
274              
275             Before Perl 5.8.8, L called with three arguments would
276             ignore L<${^OPEN}|perlvar/${^OPEN}> and thus any lexical default layers.
277             L<[perl #8168]|https://github.com/Perl/perl5/issues/8168>
278              
279             =item *
280              
281             Before Perl 5.8.9, the C<:crlf> layer did not preserve the C<:utf8> flag from
282             an earlier encoding layer, resulting in an improper translation of the bytes.
283             This can be worked around by adding the C<:utf8> pseudo-layer after C<:crlf>
284             (even if it is not a UTF-8 encoding).
285              
286             =item *
287              
288             Before Perl 5.14, the C<:crlf> layer does not properly apply on top of another
289             layer, such as an encoding layer, if it had also been applied earlier in the
290             stack such as is default on Windows. Thus you could not usefully use a layer
291             like C<:encoding(UTF-16BE)> with a following C<:crlf>.
292             L<[perl #8325]|https://github.com/Perl/perl5/issues/8325>
293              
294             =item *
295              
296             Before Perl 5.14, the C<:pop>, C<:utf8>, or C<:bytes> pseudo-layers did not
297             allow stacking further layers, like C<:pop:crlf>.
298             L<[perl #11054]|https://github.com/perl/perl5/issues/11054>
299              
300             =item *
301              
302             Before Perl 5.14, the C<:raw> pseudo-layer reset the handle to an unbuffered
303             state, rather than just removing text translation layers as when calling
304             L with no layers.
305             L<[perl #10904]|https://github.com/perl/perl5/issues/10904>
306              
307             =item *
308              
309             Before Perl 5.14, the C<:raw> pseudo-layer did not work properly with in-memory
310             scalar handles.
311              
312             =item *
313              
314             Before Perl 5.16, L and L are
315             affected by lexical default layers when loading the source file, leading to
316             unexpected results. L<[perl #11541]|https://github.com/perl/perl5/issues/11541>
317              
318             =back
319              
320             =head1 BUGS
321              
322             Report any issues on the public bugtracker.
323              
324             =head1 AUTHOR
325              
326             Dan Book
327              
328             =head1 COPYRIGHT AND LICENSE
329              
330             This software is Copyright (c) 2020 by Dan Book.
331              
332             This is free software, licensed under:
333              
334             The Artistic License 2.0 (GPL Compatible)
335              
336             =head1 SEE ALSO
337              
338             L, L