File Coverage

blib/lib/Dist/Zilla/Role/File.pm
Criterion Covered Total %
statement 51 55 92.7
branch 12 14 85.7
condition n/a
subroutine 14 16 87.5
pod 1 1 100.0
total 78 86 90.7


line stmt bran cond sub pod time code
1             # ABSTRACT: something that can act like a file
2              
3             use Moose::Role;
4 52     52   35927  
  52         5798  
  52         369  
5             use Dist::Zilla::Pragmas;
6 52     52   267017  
  52         132  
  52         431  
7             use Dist::Zilla::Types qw(_Filename);
8 52     52   1881 use Moose::Util::TypeConstraints;
  52         145  
  52         662  
9 52     52   119379 use Try::Tiny;
  52         203  
  52         485  
10 52     52   112823  
  52         132  
  52         3906  
11             use namespace::autoclean;
12 52     52   371  
  52         167  
  52         383  
13             with 'Dist::Zilla::Role::StubBuild';
14              
15             #pod =head1 DESCRIPTION
16             #pod
17             #pod This role describes a file that may be written into the shipped distribution.
18             #pod
19             #pod =attr name
20             #pod
21             #pod This is the name of the file to be written out.
22             #pod
23             #pod =cut
24              
25             has name => (
26             is => 'rw',
27             isa => _Filename,
28             required => 1,
29             );
30              
31             #pod =attr added_by
32             #pod
33             #pod This is a list of strings describing when and why the file was added
34             #pod to the distribution and when it was updated (its content, filename, or other attributes). It will
35             #pod generally be updated by a plugin implementing the
36             #pod L<FileMunger|Dist::Zilla::Role::FileMunger> role. Its accessor will return
37             #pod the list of strings, concatenated with C<'; '>.
38             #pod
39             #pod =cut
40              
41             has added_by => (
42             isa => 'ArrayRef[Str]',
43             lazy => 1,
44             default => sub { [] },
45             traits => ['Array'],
46             init_arg => undef,
47             handles => {
48             _push_added_by => 'push',
49             added_by => [ join => '; ' ],
50             },
51             );
52              
53             around name => sub {
54             my $orig = shift;
55             my $self = shift;
56             if (@_) {
57             my ($pkg, $line) = $self->_caller_of('name');
58             $self->_push_added_by(sprintf("filename set by %s (%s line %s)", $self->_caller_plugin_name, $pkg, $line));
59             }
60             return $self->$orig(@_);
61             };
62              
63             my ($self, $function) = @_;
64              
65 786     786   1968 for (my $level = 1; $level < 50; ++$level)
66             {
67 786         2431 my @frame = caller($level);
68             last if not defined $frame[0];
69 2104         15650 return ( (caller($level))[0,2] ) if $frame[3] =~ m/::${function}$/;
70 2104 50       5203 }
71 2104 100       19582 return 'unknown', '0';
72             }
73 0         0  
74             my $self = shift;
75              
76             for (my $level = 1; $level < 50; ++$level)
77 786     786   2004 {
78             my @frame = caller($level);
79 786         2281 last if not defined $frame[0];
80             return $1 if $frame[0] =~ m/^Dist::Zilla::Plugin::(.+)$/;
81 2144         9817 }
82 2144 100       4976 return 'unknown';
83 2140 100       41757 }
84              
85 4         174 #pod =attr mode
86             #pod
87             #pod This is the mode with which the file should be written out. It's an integer
88             #pod with the usual C<chmod> semantics. It defaults to 0644.
89             #pod
90             #pod =cut
91              
92             my $safe_file_mode = subtype(
93             as 'Int',
94             where { not( $_ & 0002) },
95             message { "file mode would be world-writeable" }
96             );
97              
98             has mode => (
99             is => 'rw',
100             isa => $safe_file_mode,
101             default => 0644,
102             );
103              
104             requires 'encoding';
105             requires 'content';
106             requires 'encoded_content';
107              
108             #pod =method is_bytes
109             #pod
110             #pod Returns true if the C<encoding> is bytes. When true, accessing
111             #pod C<content> will be an error.
112             #pod
113             #pod =cut
114              
115             my ($self) = @_;
116             return $self->encoding eq 'bytes';
117             }
118              
119 616     616 1 1394 my ($self, $text) = @_;
120 616         18322 my $enc = $self->encoding;
121             if ( $self->is_bytes ) {
122             return $text; # XXX hope you were right that it really was bytes
123             }
124 173     173   533 else {
125 173         5229 require Encode;
126 173 50       640 my $bytes =
127 0         0 try { Encode::encode($enc, $text, Encode::FB_CROAK()) }
128             catch { $self->_throw("encode $enc" => $_) };
129             return $bytes;
130 173         1050 }
131             }
132 173     173   9479  
133 173     0   1681 my ($self, $bytes) = @_;
  0         0  
134 173         18148 my $enc = $self->encoding;
135             if ( $self->is_bytes ) {
136             $self->_throw(decode => "Can't decode text from 'bytes' encoding");
137             }
138             else {
139 177     177   613 require Encode;
140 177         5176 my $text =
141 177 100       586 try { Encode::decode($enc, $bytes, Encode::FB_CROAK()) }
142 3         18 catch { $self->_throw("decode $enc" => $_) };
143              
144             # Okay, look, buddy… If you're using a BOM on UTF-8, that's fine. You can
145 174         1059 # use it. You're just not going to get it back. If we don't do this, the
146             # sequence of events will be:
147 174     174   10619 # * read file from UTF-8-BOM file on disk
148 174     0   1714 # * end up with FEFF as first character of file
  0         0  
149             # * pass file content to PPI
150             # * PPI blows up
151             #
152             # I'm not going to try to account for the BOM and add it back. It's awful!
153             #
154             # Meanwhile, if you're using UTF-16, you can get the BOM handled by picking
155             # the right encoding type, I think. -- rjbs, 2016-04-24
156             $enc =~ /^utf-?8$/i && $text =~ s/\A\x{FEFF}//;
157              
158             return $text;
159             }
160             }
161              
162 174 100       15849 my ($self, $op, $msg) = @_;
163             my ($name, $added_by) = map {; $self->$_ } qw/name added_by/;
164 174         6156 confess(
165             "Could not $op $name; $added_by; error was: $msg; maybe you need the [Encoding] plugin to specify an encoding"
166             );
167             }
168              
169 3     3   10 1;
170 3         7  
  6         124  
171 3         1498  
172             =pod
173              
174             =encoding UTF-8
175              
176             =head1 NAME
177              
178             Dist::Zilla::Role::File - something that can act like a file
179              
180             =head1 VERSION
181              
182             version 6.028
183              
184             =head1 DESCRIPTION
185              
186             This role describes a file that may be written into the shipped distribution.
187              
188             =head1 PERL VERSION
189              
190             This module should work on any version of perl still receiving updates from
191             the Perl 5 Porters. This means it should work on any version of perl released
192             in the last two to three years. (That is, if the most recently released
193             version is v5.40, then this module should work on both v5.40 and v5.38.)
194              
195             Although it may work on older versions of perl, no guarantee is made that the
196             minimum required version will not be increased. The version may be increased
197             for any reason, and there is no promise that patches will be accepted to lower
198             the minimum required perl.
199              
200             =head1 ATTRIBUTES
201              
202             =head2 name
203              
204             This is the name of the file to be written out.
205              
206             =head2 added_by
207              
208             This is a list of strings describing when and why the file was added
209             to the distribution and when it was updated (its content, filename, or other attributes). It will
210             generally be updated by a plugin implementing the
211             L<FileMunger|Dist::Zilla::Role::FileMunger> role. Its accessor will return
212             the list of strings, concatenated with C<'; '>.
213              
214             =head2 mode
215              
216             This is the mode with which the file should be written out. It's an integer
217             with the usual C<chmod> semantics. It defaults to 0644.
218              
219             =head1 METHODS
220              
221             =head2 is_bytes
222              
223             Returns true if the C<encoding> is bytes. When true, accessing
224             C<content> will be an error.
225              
226             =head1 AUTHOR
227              
228             Ricardo SIGNES 😏 <cpan@semiotic.systems>
229              
230             =head1 COPYRIGHT AND LICENSE
231              
232             This software is copyright (c) 2022 by Ricardo SIGNES.
233              
234             This is free software; you can redistribute it and/or modify it under
235             the same terms as the Perl 5 programming language system itself.
236              
237             =cut