File Coverage

blib/lib/Module/Build/Notes.pm
Criterion Covered Total %
statement 91 91 100.0
branch 30 38 78.9
condition 13 20 65.0
subroutine 14 14 100.0
pod 1 8 12.5
total 149 171 87.1


line stmt bran cond sub pod time code
1             package Module::Build::Notes;
2              
3             # A class for persistent hashes
4              
5 293     293   2183 use strict;
  293         679  
  293         8879  
6 293     293   1522 use warnings;
  293         564  
  293         13892  
7             our $VERSION = '0.4234';
8             $VERSION = eval $VERSION;
9 293     293   1768 use Data::Dumper;
  293         530  
  293         13832  
10 293     293   1850 use Module::Build::Dumper;
  293         613  
  293         316504  
11              
12             sub new {
13 3360     3360 0 18713 my ($class, %args) = @_;
14 3360 50       13677 my $file = delete $args{file} or die "Missing required parameter 'file' to new()";
15 3360         56598 my $self = bless {
16             disk => {},
17             new => {},
18             file => $file,
19             %args,
20             }, $class;
21             }
22              
23             sub restore {
24 2862     2862 0 9780 my $self = shift;
25              
26 2862 50       146056 open(my $fh, '<', $self->{file}) or die "Can't read $self->{file}: $!";
27 2862         10055 $self->{disk} = eval do {local $/; <$fh>};
  2862         16343  
  2862         411390  
28 2862 50       20074 die $@ if $@;
29 2862         40928 close $fh;
30 2862         23507 $self->{new} = {};
31             }
32              
33             sub access {
34 127     127 0 460 my $self = shift;
35 127 100       716 return $self->read() unless @_;
36              
37 44         255 my $key = shift;
38 44 100       261 return $self->read($key) unless @_;
39              
40 25         103 my $value = shift;
41 25         229 $self->write({ $key => $value });
42 25         123 return $self->read($key);
43             }
44              
45             sub has_data {
46 183     183 0 541 my $self = shift;
47 183         402 return keys %{$self->read()} > 0;
  183         664  
48             }
49              
50             sub exists {
51 2     2 0 18 my ($self, $key) = @_;
52 2   33     67 return exists($self->{new}{$key}) || exists($self->{disk}{$key});
53             }
54              
55             sub read {
56 467     467 0 1325 my $self = shift;
57              
58 467 100       1817 if (@_) {
59             # Return 1 key as a scalar
60 44         111 my $key = shift;
61 44 100       169 return $self->{new}{$key} if exists $self->{new}{$key};
62 42         305 return $self->{disk}{$key};
63             }
64              
65             # Return all data
66 423         3215 my $out = (keys %{$self->{new}}
67 7         110 ? {%{$self->{disk}}, %{$self->{new}}}
  7         102  
68 423 100       816 : $self->{disk});
69 423 100       3787 return wantarray ? %$out : $out;
70             }
71              
72             sub _same {
73 95     95   456 my ($self, $x, $y) = @_;
74 95 0 33     617 return 1 if !defined($x) and !defined($y);
75 95 100 66     1012 return 0 if !defined($x) or !defined($y);
76 93         705 return $x eq $y;
77             }
78              
79             sub write {
80 252     252 1 1185 my ($self, $href) = @_;
81 252   100     1514 $href ||= {};
82              
83 252         1609 @{$self->{new}}{ keys %$href } = values %$href; # Merge
  252         1409  
84              
85             # Do some optimization to avoid unnecessary writes
86 252         933 foreach my $key (keys %{ $self->{new} }) {
  252         2088  
87 233 100       1439 next if ref $self->{new}{$key};
88 230 100 66     3094 next if ref $self->{disk}{$key} or !exists $self->{disk}{$key};
89 95 100       770 delete $self->{new}{$key} if $self->_same($self->{new}{$key}, $self->{disk}{$key});
90             }
91              
92 252 50       1809 if (my $file = $self->{file}) {
93 252         9918 my ($vol, $dir, $base) = File::Spec->splitpath($file);
94 252         4741 $dir = File::Spec->catpath($vol, $dir, '');
95 252 100 66     9111 return unless -e $dir && -d $dir; # The user needs to arrange for this
96              
97 224 100 100     4007 return if -e $file and !keys %{ $self->{new} }; # Nothing to do
  221         2802  
98              
99 102         364 @{$self->{disk}}{ keys %{$self->{new}} } = values %{$self->{new}}; # Merge
  102         496  
  102         379  
  102         587  
100 102         769 $self->_dump($file, $self->{disk});
101              
102 102         1245 $self->{new} = {};
103             }
104 102         786 return $self->read;
105             }
106              
107             sub _dump {
108 102     102   488 my ($self, $file, $data) = @_;
109              
110 102 50       20416 open(my $fh, '>', $file) or die "Can't create '$file': $!";
111 102         713 print {$fh} Module::Build::Dumper->_data_dump($data);
  102         2782  
112 102         39196 close $fh;
113             }
114              
115             my $orig_template = do { local $/; <DATA> };
116             close DATA;
117              
118             sub write_config_data {
119 1     1 0 20 my ($self, %args) = @_;
120              
121 1         13 my $template = $orig_template;
122 1         36 $template =~ s/NOTES_NAME/$args{config_module}/g;
123 1         24 $template =~ s/MODULE_NAME/$args{module}/g;
124 1         21 $template =~ s/=begin private\n//;
125 1         25 $template =~ s/=end private/=cut/;
126              
127             # strip out private POD markers we use to keep pod from being
128             # recognized for *this* source file
129 1         32 $template =~ s{$_\n}{} for '=begin private', '=end private';
130              
131 1 50       75 open(my $fh, '>', $args{file}) or die "Can't create '$args{file}': $!";
132 1         4 print {$fh} $template;
  1         20  
133 1         4 print {$fh} "\n__DATA__\n";
  1         3  
134 1         3 print {$fh} Module::Build::Dumper->_data_dump([$args{config_data}, $args{feature}, $args{auto_features}]);
  1         11  
135 1         182 close $fh;
136             }
137              
138             1;
139              
140              
141             =head1 NAME
142              
143             Module::Build::Notes - Create persistent distribution configuration modules
144              
145             =head1 DESCRIPTION
146              
147             This module is used internally by Module::Build to create persistent
148             configuration files that can be installed with a distribution. See
149             L<Module::Build::ConfigData> for an example.
150              
151             =head1 AUTHOR
152              
153             Ken Williams <kwilliams@cpan.org>
154              
155             =head1 COPYRIGHT
156              
157             Copyright (c) 2001-2006 Ken Williams. All rights reserved.
158              
159             This library is free software; you can redistribute it and/or
160             modify it under the same terms as Perl itself.
161              
162             =head1 SEE ALSO
163              
164             perl(1), L<Module::Build>(3)
165              
166             =cut
167              
168             __DATA__
169             package NOTES_NAME;
170             use strict;
171             my $arrayref = eval do {local $/; <DATA>}
172             or die "Couldn't load ConfigData data: $@";
173             close DATA;
174             my ($config, $features, $auto_features) = @$arrayref;
175              
176             sub config { $config->{$_[1]} }
177              
178             sub set_config { $config->{$_[1]} = $_[2] }
179             sub set_feature { $features->{$_[1]} = 0+!!$_[2] } # Constrain to 1 or 0
180              
181             sub auto_feature_names { sort grep !exists $features->{$_}, keys %$auto_features }
182              
183             sub feature_names {
184             my @features = (sort keys %$features, auto_feature_names());
185             @features;
186             }
187              
188             sub config_names { sort keys %$config }
189              
190             sub write {
191             my $me = __FILE__;
192              
193             # Can't use Module::Build::Dumper here because M::B is only a
194             # build-time prereq of this module
195             require Data::Dumper;
196              
197             my $mode_orig = (stat $me)[2] & 07777;
198             chmod($mode_orig | 0222, $me); # Make it writeable
199             open(my $fh, '+<', $me) or die "Can't rewrite $me: $!";
200             seek($fh, 0, 0);
201             while (<$fh>) {
202             last if /^__DATA__$/;
203             }
204             die "Couldn't find __DATA__ token in $me" if eof($fh);
205              
206             seek($fh, tell($fh), 0);
207             my $data = [$config, $features, $auto_features];
208             print($fh 'do{ my '
209             . Data::Dumper->new([$data],['x'])->Purity(1)->Dump()
210             . '$x; }' );
211             truncate($fh, tell($fh));
212             close $fh;
213              
214             chmod($mode_orig, $me)
215             or warn "Couldn't restore permissions on $me: $!";
216             }
217              
218             sub feature {
219             my ($package, $key) = @_;
220             return $features->{$key} if exists $features->{$key};
221              
222             my $info = $auto_features->{$key} or return 0;
223              
224             require Module::Build; # XXX should get rid of this
225             foreach my $type (sort keys %$info) {
226             my $prereqs = $info->{$type};
227             next if $type eq 'description' || $type eq 'recommends';
228              
229             foreach my $modname (sort keys %$prereqs) {
230             my $status = Module::Build->check_installed_status($modname, $prereqs->{$modname});
231             if ((!$status->{ok}) xor ($type =~ /conflicts$/)) { return 0; }
232             if ( ! eval "require $modname; 1" ) { return 0; }
233             }
234             }
235             return 1;
236             }
237              
238             =begin private
239              
240             =head1 NAME
241              
242             NOTES_NAME - Configuration for MODULE_NAME
243              
244             =head1 SYNOPSIS
245              
246             use NOTES_NAME;
247             $value = NOTES_NAME->config('foo');
248             $value = NOTES_NAME->feature('bar');
249              
250             @names = NOTES_NAME->config_names;
251             @names = NOTES_NAME->feature_names;
252              
253             NOTES_NAME->set_config(foo => $new_value);
254             NOTES_NAME->set_feature(bar => $new_value);
255             NOTES_NAME->write; # Save changes
256              
257              
258             =head1 DESCRIPTION
259              
260             This module holds the configuration data for the C<MODULE_NAME>
261             module. It also provides a programmatic interface for getting or
262             setting that configuration data. Note that in order to actually make
263             changes, you'll have to have write access to the C<NOTES_NAME>
264             module, and you should attempt to understand the repercussions of your
265             actions.
266              
267              
268             =head1 METHODS
269              
270             =over 4
271              
272             =item config($name)
273              
274             Given a string argument, returns the value of the configuration item
275             by that name, or C<undef> if no such item exists.
276              
277             =item feature($name)
278              
279             Given a string argument, returns the value of the feature by that
280             name, or C<undef> if no such feature exists.
281              
282             =item set_config($name, $value)
283              
284             Sets the configuration item with the given name to the given value.
285             The value may be any Perl scalar that will serialize correctly using
286             C<Data::Dumper>. This includes references, objects (usually), and
287             complex data structures. It probably does not include transient
288             things like filehandles or sockets.
289              
290             =item set_feature($name, $value)
291              
292             Sets the feature with the given name to the given boolean value. The
293             value will be converted to 0 or 1 automatically.
294              
295             =item config_names()
296              
297             Returns a list of all the names of config items currently defined in
298             C<NOTES_NAME>, or in scalar context the number of items.
299              
300             =item feature_names()
301              
302             Returns a list of all the names of features currently defined in
303             C<NOTES_NAME>, or in scalar context the number of features.
304              
305             =item auto_feature_names()
306              
307             Returns a list of all the names of features whose availability is
308             dynamically determined, or in scalar context the number of such
309             features. Does not include such features that have later been set to
310             a fixed value.
311              
312             =item write()
313              
314             Commits any changes from C<set_config()> and C<set_feature()> to disk.
315             Requires write access to the C<NOTES_NAME> module.
316              
317             =back
318              
319              
320             =head1 AUTHOR
321              
322             C<NOTES_NAME> was automatically created using C<Module::Build>.
323             C<Module::Build> was written by Ken Williams, but he holds no
324             authorship claim or copyright claim to the contents of C<NOTES_NAME>.
325              
326             =end private
327