File Coverage

blib/lib/Config/MVP/Writer/INI.pm
Criterion Covered Total %
statement 62 73 84.9
branch 26 32 81.2
condition 5 8 62.5
subroutine 10 11 90.9
pod 1 1 100.0
total 104 125 83.2


line stmt bran cond sub pod time code
1             # vim: set ts=2 sts=2 sw=2 expandtab smarttab:
2             #
3             # This file is part of Config-MVP-Writer-INI
4             #
5             # This software is copyright (c) 2012 by Randy Stauner.
6             #
7             # This is free software; you can redistribute it and/or modify it under
8             # the same terms as the Perl 5 programming language system itself.
9             #
10 3     3   121035 use strict;
  3         5  
  3         112  
11 3     3   13 use warnings;
  3         6  
  3         196  
12              
13             package Config::MVP::Writer::INI;
14             # git description: v0.003-3-gfc75cb5
15              
16             our $AUTHORITY = 'cpan:RWSTAUNER';
17             # ABSTRACT: Build an INI file for Config::MVP
18             $Config::MVP::Writer::INI::VERSION = '0.004';
19 3     3   13 use Moose;
  3         4  
  3         24  
20 3     3   15794 use Moose::Util::TypeConstraints;
  3         6  
  3         28  
21 3     3   4814 use List::Util ();
  3         10  
  3         2542  
22              
23              
24             has spacing => (
25             is => 'ro',
26             isa => enum([qw( none all payload )]),
27             default => 'payload',
28             );
29              
30              
31             has strip_bundle_prefix => (
32             is => 'ro',
33             isa => 'Bool',
34             default => 1,
35             );
36              
37              
38              
39             has _rewrite_package => (
40             is => 'ro',
41             isa => 'CodeRef',
42             traits => ['Code'],
43             init_arg => 'rewrite_package',
44             predicate => 'can_rewrite_package',
45             handles => {
46             rewrite_package => 'execute',
47             },
48             );
49              
50             sub ini_string {
51 11     11 1 534 my ($self, $sections) = @_;
52              
53             # TODO: @$sections = $self->_simplify_bundles(@$sections) if configured
54              
55 11         30 my @strings = map { $self->_ini_section($_) } @$sections;
  53         112  
56              
57 11         410 my $spacing = $self->spacing;
58              
59 11 100       52 if( $spacing eq 'all' ){
    100          
60             # put a blank line after each section
61 1         5 @strings = map { "$_\n" } @strings;
  8         21  
62             }
63             elsif( $spacing eq 'payload' ){
64             # put a blank line around any section with a payload
65 9 100       17 @strings = map { /\n.+/ ? "\n$_\n" : $_ } @strings;
  37         105  
66             }
67              
68 11         42 my $ini = join '', @strings;
69              
70             # don't need to start with a newline
71 11         30 $ini =~ s/\A\n+//;
72             # don't need more than two together (single blank line)
73 11         65 $ini =~ s/(?<=\n\n)\n+//g;
74             # one newline at the end is sufficient
75 11         221 $ini =~ s/\n*\z/\n/;
76              
77 11         505 return $ini;
78             }
79              
80             sub _ini_section {
81 53     53   60 my ($self, $section) = @_;
82              
83             # break the reference, make one if we don't have one
84 53 100       193 $section = ref($section) eq 'ARRAY' ? [@$section] : [$section];
85              
86 53 100       125 my $config = ref($section->[-1]) eq 'HASH' ? pop @$section : {};
87 53         67 my $name = shift @$section;
88 53   66     128 my $package = shift @$section || $name;
89              
90 53 100       2236 if( $self->can_rewrite_package ){
91             # copy the value and offer it as $_
92 26         31 local $_ = $package;
93             # only use if something was returned
94 26   66     943 $package = $self->rewrite_package($_) || $package;
95             }
96              
97             # this name matching junk could be better
98             {
99             # make leading punctuation optional for this comparison
100 53         189 my ($prefix, $moniker) = ($package =~ m/^(\W*)(.+)$/);
  53         205  
101              
102             # Don't print the name if it's the same as the package moniker
103             # (ignoring possible bundle prefix and possible leading punctuation).
104 53 100       2967 if( $name =~ m{^([^/]+/)*(\Q$prefix\E)?\Q$moniker\E$} ){
    50          
105 19         39 $name = ''
106             }
107             # else (if configured) just strip the whole prefix regardless
108             elsif( $self->strip_bundle_prefix ){
109 34         70 $name =~ s{^\@.+/}{};
110             }
111             }
112              
113             # Only show the name if different from the package moniker
114 53 100       180 my $ini = "[$package" . ($name ? " / $name" : '') . "]\n";
115              
116 53         118 $ini .= $self->_ini_section_config($config);
117              
118 53         191 return $ini;
119             }
120              
121             # TODO: rewrite_package
122             # reverse RewritePrefix
123             #$package =~ s/Dist::Zilla::(Plugin(Bundle)?)::/$2 ? '@' : ''/e
124             #or $package = "=$package";
125              
126             sub _simplify_bundles {
127 0     0   0 my ($self, @sections) = @_;
128              
129 0         0 my @simplified;
130             # for specified bundles just show [@Bundle] instead of each plugin
131             #my %bundles = map { ($_ => 0) } @{ $opts->{bundles} || [] };
132             my %bundles;
133              
134 0         0 foreach my $section ( @sections ){
135 0         0 my ($name) = @$section;
136             # just list the bundle not each individual plugin
137 0         0 foreach my $bundle ( keys %bundles ){
138 0 0       0 if( $name =~ /\@${bundle}\b/ ){
139 0 0       0 push @simplified, '@' . $bundle
140             unless $bundles{ $bundle }++;
141 0         0 next;
142             }
143             else {
144 0         0 push @simplified, $section;
145             }
146             }
147             }
148              
149 0         0 return @simplified;
150             }
151              
152             sub _ini_section_config {
153 53     53   69 my ($self, $config) = @_;
154              
155 53 100 50     265 return ''
156             unless $config && scalar keys %$config;
157              
158 16         21 my @lines;
159 16         41 my $len = List::Util::max(map { length } keys %$config);
  23         88  
160              
161 16         54 foreach my $k ( sort keys %$config ){
162 23         30 my $v = $config->{ $k };
163 23 100       48 $v = '' if !defined $v;
164 28 100       150 push @lines,
165             # don't end a line with "=\x20" (when the value is '')
166 0         0 map { sprintf "%-*s =%s\n", $len, $k, (length($_) ? ' ' . $_ : '') }
167             # one k=v line per array item
168             ref $v eq 'ARRAY'
169             ? @$v
170             # if there are newlines, assume 1 k=v per line
171             : $v =~ /\n/
172             # but skip blanks
173 23 50       74 ? grep { $_ } split /\n/, $v
    100          
174             # just one plain k=v line
175             : $v
176             }
177              
178 16         58 return join '', @lines;
179             }
180              
181 3     3   17 no Moose;
  3         5  
  3         19  
182 3     3   474 no Moose::Util::TypeConstraints;
  3         4  
  3         16  
183             __PACKAGE__->meta->make_immutable;
184             1;
185              
186             __END__
187              
188             =pod
189              
190             =encoding UTF-8
191              
192             =for :stopwords Randy Stauner ACKNOWLEDGEMENTS Etheridge Karen TODO cpan testmatrix url
193             annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata
194             placeholders metacpan
195              
196             =head1 NAME
197              
198             Config::MVP::Writer::INI - Build an INI file for Config::MVP
199              
200             =head1 VERSION
201              
202             version 0.004
203              
204             =head1 SYNOPSIS
205              
206             my $ini = Config::MVP::Writer::INI->new->ini_string(\@sections);
207              
208             =head1 DESCRIPTION
209              
210             This class takes a collection of L<Config::MVP> style data structures
211             and writes them to a string in INI format.
212              
213             One usage example would be to create a roughly equivalent INI file
214             from the output of a plugin bundle (L<Dist::Zilla>, L<Pod::Weaver>, etc.).
215              
216             The author makes no claim that this would actually be useful to anyone.
217              
218             =head1 ATTRIBUTES
219              
220             =head2 spacing
221              
222             Defines the spacing between sections.
223             Must be one of the following:
224              
225             =over 4
226              
227             =item payload
228              
229             (Default) Put blank lines around sections with a payload
230              
231             =item all
232              
233             Put a blank line between all sections
234              
235             =item none
236              
237             No blank lines
238              
239             =back
240              
241             =head2 strip_bundle_prefix
242              
243             Boolean: Always remove the leading C<@BundleName/> part of a section name.
244             This cuts down on the noise when the name is actually different
245             from the package moniker (but the prefix isn't desired). Defaults to true.
246              
247             =head2 rewrite_package
248              
249             This attribute is a coderef that will be used to munge the package name
250             of each section. The package will be passed as the only argument
251             (and also available as C<$_>) and should return the translation.
252             If nothing is returned the original package will be used.
253              
254             This can be used to flavor the INI for a particular application.
255             For example:
256              
257             rewrite_package => sub { s/^MyApp::Plugin::/-/r; }
258              
259             will transform an array ref of
260              
261             [ Stinky => 'MyApp::Plugin::Nickname' => {real_name => "Dexter"} ]
262              
263             into an INI string of
264              
265             [-Nickname / Stinky]
266             real_name = Dexter
267              
268             =head1 METHODS
269              
270             =head2 ini_string
271              
272             This takes an array ref of array refs,
273             each one being a C<Config::MVP> style section specification:
274              
275             [
276             [ $name, $package, \%payload ],
277             ]
278              
279             and returns a string.
280              
281             For convenience a few specification shortcuts are recognized:
282              
283             $name => [ $name, $name, {} ]
284             [ $name ] => [ $name, $name, {} ]
285             [ $name, $package ] => [ $name, $package, {} ]
286             [ $name, \%payload ] => [ $name, $name, \%payload ]
287              
288             =for comment has simplify_bundles => (
289             is => 'ro',
290             isa => union([qw( ArrayRef Bool )]),
291             );
292              
293             =for test_synopsis my @sections;
294              
295             =head1 WARNING
296              
297             This code is very much in an alpha state and the API is likely to change.
298             As always, suggestions, bug reports, patches, and pull requests are welcome.
299              
300             =head1 TODO
301              
302             =over 4
303              
304             =item *
305              
306             Documentation
307              
308             =item *
309              
310             More tests
311              
312             =item *
313              
314             Allow payload to be an arrayref for explicit ordering
315              
316             =back
317              
318             =head1 SUPPORT
319              
320             =head2 Perldoc
321              
322             You can find documentation for this module with the perldoc command.
323              
324             perldoc Config::MVP::Writer::INI
325              
326             =head2 Websites
327              
328             The following websites have more information about this module, and may be of help to you. As always,
329             in addition to those websites please use your favorite search engine to discover more resources.
330              
331             =over 4
332              
333             =item *
334              
335             MetaCPAN
336              
337             A modern, open-source CPAN search engine, useful to view POD in HTML format.
338              
339             L<http://metacpan.org/release/Config-MVP-Writer-INI>
340              
341             =back
342              
343             =head2 Bugs / Feature Requests
344              
345             Please report any bugs or feature requests by email to C<bug-config-mvp-writer-ini at rt.cpan.org>, or through
346             the web interface at L<https://rt.cpan.org/Public/Bug/Report.html?Queue=Config-MVP-Writer-INI>. You will be automatically notified of any
347             progress on the request by the system.
348              
349             =head2 Source Code
350              
351              
352             L<https://github.com/rwstauner/Config-MVP-Writer-INI>
353              
354             git clone https://github.com/rwstauner/Config-MVP-Writer-INI.git
355              
356             =head1 AUTHOR
357              
358             Randy Stauner <rwstauner@cpan.org>
359              
360             =head1 CONTRIBUTOR
361              
362             =for stopwords Karen Etheridge
363              
364             Karen Etheridge <ether@cpan.org>
365              
366             =head1 COPYRIGHT AND LICENSE
367              
368             This software is copyright (c) 2012 by Randy Stauner.
369              
370             This is free software; you can redistribute it and/or modify it under
371             the same terms as the Perl 5 programming language system itself.
372              
373             =cut