File Coverage

blib/lib/Data/Section/Writer.pm
Criterion Covered Total %
statement 148 151 98.0
branch 35 50 70.0
condition 13 17 76.4
subroutine 22 22 100.0
pod 6 7 85.7
total 224 247 90.6


line stmt bran cond sub pod time code
1 3     3   545264 use warnings;
  3         5  
  3         144  
2 3     3   44 use 5.020;
  3         12  
3 3     3   399 use experimental qw( signatures );
  3         3627  
  3         18  
4 3     3   1175 use stable qw( postderef );
  3         689  
  3         17  
5 3     3   875 use true;
  3         13609  
  3         15  
6              
7             package Data::Section::Writer 0.05 {
8              
9             # ABSTRACT: Write __DATA__ section files for Data::Section, Data::Section::Simple or Mojo::Loader::data_section
10              
11              
12 3     3   3686 use Path::Tiny ();
  3         23857  
  3         75  
13 3     3   18 use Carp ();
  3         8  
  3         51  
14 3     3   1185 use Class::Tiny qw( perl_filename _files _same _formats );
  3         3392  
  3         20  
15 3     3   2881 use Ref::Util qw( is_coderef is_blessed_ref is_plain_arrayref );
  3         4775  
  3         309  
16 3     3   1068 use MIME::Base64 qw(encode_base64);
  3         1507  
  3         148  
17 3     3   1827 use File::Temp ();
  3         34333  
  3         2455  
18              
19 5     5 0 481599 sub BUILD ($self, $) {
  5         11  
  5         6  
20              
21             # use the callers filename if not provided.
22 5 100       129 unless(defined $self->perl_filename) {
23 2         28 my(undef, $fn) = caller 2;
24 2         38 $self->perl_filename($fn);
25             }
26              
27             # upgrade to Path::Tiny if it is not already
28 5 50 66     83 unless(is_blessed_ref $self->perl_filename && $self->isa('Path::Tiny')) {
29 5         92 $self->perl_filename(Path::Tiny->new($self->perl_filename));
30             }
31              
32 5         457 $self->_files({});
33 5         75 $self->_formats({});
34              
35             }
36              
37              
38 7     7 1 2907 sub add_file ($self, $filename, $content, $encoding=undef) {
  7         10  
  7         15  
  7         7  
  7         26  
  7         7  
39 7 50 66     26 Carp::croak("Unknown encoding $encoding") if defined $encoding && $encoding ne 'base64';
40 7         138 $self->_files->{"$filename"} = [ $content, $encoding ];
41 7         42 return $self;
42             }
43              
44 23     23   27 sub _render_file ($self, $filename, $data) {
  23         24  
  23         28  
  23         43  
  23         38  
45 23         35 my $text = "@@ $filename";
46 23 100       73 $text .= " (" . $data->[1] . ")" if defined $data->[1];
47 23         27 $text .= "\n";
48              
49 23         29 my $content = $data->[0];
50              
51 23 100 100     432 if($filename =~ /\.(.*?)\z/ && ($self->_formats->{$1} // [])->@*) {
      66        
52 1         6 my $ext = $1;
53 1         11 $content = $_->($self, $content) for $self->_formats->{$ext}->@*;
54             }
55              
56 23 100 66     1203 if(defined $data->[1] && $data->[1] eq 'base64') {
57 10         48 $text .= encode_base64($data->[0]);
58             } else {
59 13         27 $text .= $content;
60             }
61 23         34 chomp $text;
62 23         82 return $text;
63             }
64              
65              
66 13     13 1 3352 sub render_section ($self) {
  13         27  
  13         23  
67 13         263 my $files = $self->_files;
68 13 100       73 return "__DATA__\n" unless %$files;
69             return join("\n",
70             "__DATA__",
71 11         53 (map { $self->_render_file($_, $files->{$_}) } sort keys $files->%*),
  23         58  
72             ''
73             );
74             }
75              
76              
77 9     9 1 10557 sub update_file ($self) {
  9         15  
  9         16  
78 9         17 my $perl;
79             my $orig;
80              
81 9 100       250 if(-f $self->perl_filename) {
82 8         355 $orig = $perl = $self->perl_filename->slurp_utf8;
83              
84 8 100       2403 if($perl =~ /^__DATA__/) {
85 1         3 $perl = '';
86             } else {
87             # read the file in, removing __DATA__ and everything after that
88             # if there is no __DATA__ section then leave unchanged.
89 7         37 $perl =~ s/(?<=\n)__DATA__.*//s;
90              
91             # Add a new line at the end if it doesn't already exist.
92 7 100       41 $perl .= "\n" unless $perl =~ /\n\z/s;
93             }
94              
95             } else {
96 1         34 $perl = '';
97             }
98              
99 9         37 $perl .= $self->render_section;
100              
101 9 100 100     37 if(defined $orig && $orig eq $perl) {
102 1         15 $self->_same(1);
103 1         6 return $self;
104             } else {
105 8         106 $self->_same(0);
106             }
107              
108 8 100       122 if(-f $self->perl_filename) {
109 3     3   1322 use autodie qw( truncate close );
  3         38260  
  3         11  
110             # re-write the perl to the file, using the existing inode
111 7         237 my $backup = Path::Tiny->new(File::Temp::tempnam($self->perl_filename->parent, $self->perl_filename->basename));
112 7 50       2583 $self->perl_filename->copy($backup) if -f $self->perl_filename;
113 7         6994 my $fh = $self->perl_filename->openrw_utf8;
114 7         2540 truncate $fh, 0;
115 7 50       1856 print $fh $perl or die "unable to write to @{[ $self->perl_filename ]} $!";
  0         0  
116 7         34 close $fh;
117 7 50       2466 $backup->remove if -f $backup;
118             } else {
119 1         28 $self->perl_filename->spew_utf8($perl);
120             }
121              
122 8         1620 return $self;
123             }
124              
125              
126 3     3 1 931 sub unchanged ($self) {
  3         6  
  3         5  
127 3         81 return $self->_same;
128             }
129              
130              
131 1     1 1 2 sub add_format ($self, $ext, $cb) {
  1         1  
  1         2  
  1         1  
  1         1  
132 1 50       3 Carp::croak("callback is not a code reference") unless is_coderef $cb;
133 1         24 push $self->_formats->{$ext}->@*, $cb;
134 1         7 return $self;
135             }
136              
137              
138 1     1 1 11 sub add_plugin ($self, $name, %args) {
  1         1  
  1         2  
  1         1  
  1         1  
139 1 50       6 Carp::croak("plugin name must match [a-z][a-z0-9_]+, got $name")
140             unless $name =~ /^[a-z][a-z0-9_]+\z/;
141              
142 1         6 my $class = join '::', 'Data', 'Section', 'Pluggable', 'Plugin', ucfirst($name =~ s/_(.)/uc($1)/egr);
  1         7  
143 1         6 my $pm = ($class =~ s!::!/!gr) . ".pm";
144              
145 1 50       3 require $pm unless $self->_valid_plugin($class);
146              
147 1         14 my $plugin;
148 1 50       6 if($class->can("new")) {
149 0         0 $plugin = $class->new(%args);
150             } else {
151 1 50       2 if(%args) {
152 0         0 Carp::croak("extra arguments are not allowed for class plugins (hint create constructor)");
153             }
154 1         2 $plugin = $class;
155             }
156              
157 1 50       2 Carp::croak("$class is not a valid Data::Section::Pluggable plugin")
158             unless $self->_valid_plugin($plugin);
159              
160 1 50       27 if($plugin->does('Data::Section::Pluggable::Role::FormatContentPlugin')) {
161              
162 1         10 my @extensions = $plugin->extensions;
163 1 50       640 @extensions = $extensions[0]->@* if is_plain_arrayref $extensions[0];
164              
165 1 50       4 die "extensions method for $class returned no extensions" unless @extensions;
166              
167 1     1   5 my $cb = sub ($self, $content) {
  1         1  
  1         13  
  1         2  
168 1         5 return $plugin->format_content($self, $content);
169 1         4 };
170              
171 1         5 $self->add_format($_, $cb) for @extensions;
172             }
173              
174 1         9 return $self;
175             }
176              
177 2     2   2 sub _valid_plugin ($self, $plugin) {
  2         2  
  2         3  
  2         2  
178 2 50       13 $plugin->can('does') && $plugin->does('Data::Section::Pluggable::Role::FormatContentPlugin');
179             }
180             }
181              
182             __END__