File Coverage

blib/lib/Debian/Control/Stanza.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Debian::Control::Stanza - single stanza of Debian source package control file
4              
5             =head1 SYNOPSIS
6              
7             package Binary;
8             use base 'Debian::Control::Stanza';
9             use constant fields => qw( Package Depends Conflicts );
10              
11             1;
12              
13             =head1 DESCRIPTION
14              
15             Debian::Control::Stanza is the base class for
16             L and L
17             classes.
18              
19             =cut
20              
21             package Debian::Control::Stanza;
22              
23             require v5.10.0;
24              
25 7     7   2568283 use strict;
  7         15  
  7         212  
26 7     7   44 use warnings;
  7         16  
  7         354  
27              
28             our $VERSION = '0.96';
29              
30 7     7   45 use base qw( Class::Accessor Tie::IxHash );
  7         22  
  7         2877  
31              
32 7     7   29645 use Carp qw(croak);
  7         18  
  7         298  
33 7     7   1916 use Debian::Control::Stanza::CommaSeparated;
  7         46  
  7         117  
34 7     7   2093 use Debian::Dependencies;
  0            
  0            
35              
36             =head1 FIELDS
37              
38             Stanza fields are to be defined in the class method I. Typically this
39             can be done like:
40              
41             use constant fields => qw( Foo Bar Baz );
42              
43             Fields that are to contain dependency lists (as per L
44             method below) are automatically converted to instances of the
45             L class.
46              
47             =cut
48              
49             use constant fields => ();
50              
51             my %canonical;
52              
53             sub import {
54             my( $class ) = @_;
55              
56             # map the accessor name for the lower case equivalent
57             %canonical = map (
58             ( lc($_) => $_ ),
59             $class->fields,
60             );
61              
62             $class->mk_accessors( $class->fields );
63             }
64              
65             use overload '""' => \&as_string;
66              
67             =head1 CONSTRUCTOR
68              
69             =over
70              
71             =item new
72              
73             =item new( { field => value, ... } )
74              
75             Creates a new L object and optionally initializes it
76             with the supplied data. The object is hashref based and tied to L.
77              
78             You may use dashes for initial field names, but these will be converted to
79             underscores:
80              
81             my $s = Debian::Control::Stanza::Source( {Build-Depends => "perl"} );
82             print $s->Build_Depends;
83              
84             =back
85              
86             =cut
87              
88             sub new {
89             my $class = shift;
90             my $init = shift || {};
91              
92             my $self = Tie::IxHash->new;
93              
94             bless $self, $class;
95              
96             while( my($k,$v) = each %$init ) {
97             $k =~ s/-/_/g;
98             # translate field name into the accessor canonical name
99             $k = $canonical{ lc $k } || $k;
100             $self->can($k)
101             or croak "Invalid field given ($k)";
102             $self->$k($v);
103             }
104              
105             # initialize any dependency lists with empty placeholders
106             # same for comma-separated lists
107             for( $self->fields ) {
108             if ( $self->is_dependency_list($_) and not $self->$_ ) {
109             $self->$_( Debian::Dependencies->new );
110             }
111             elsif ( $self->is_comma_separated($_) and not $self->$_ ) {
112             $self->$_( Debian::Control::Stanza::CommaSeparated->new );
113             }
114             }
115              
116              
117             return $self;
118             }
119              
120             =head1 METHODS
121              
122             =over
123              
124             =item is_dependency_list($field)
125              
126             Returns true if I<$field> contains a list of dependencies. By default returns true for the following fields:
127              
128             =over
129              
130             =item Build_Depends
131              
132             =item Build_Depends_Indep
133              
134             =item Build_Conflicts
135              
136             =item Build_Conflicts_Indep
137              
138             =item Depends
139              
140             =item Conflicts
141              
142             =item Enhances
143              
144             =item Replaces
145              
146             =item Breaks
147              
148             =item Pre_Depends
149              
150             =item Recommends
151              
152             =item Suggests
153              
154             =back
155              
156             =cut
157              
158             our %dependency_list = map(
159             ( $_ => 1 ),
160             qw( Build-Depends Build-Depends-Indep Build-Conflicts Build-Conflicts-Indep
161             Depends Conflicts Enhances Replaces Breaks Pre-Depends Recommends Suggests ),
162             );
163              
164             sub is_dependency_list {
165             my( $self, $field ) = @_;
166              
167             $field =~ s/_/-/g;
168              
169             return exists $dependency_list{$field};
170             }
171              
172             =item is_comma_separated($field)
173              
174             Returns true if the given field is to contain a comma-separated list of values.
175             This is used in stringification, when considering where to wrap long lines.
176              
177             By default the following fields are flagged to contain such lists:
178              
179             =over
180              
181             =item All fields that contain dependencies (see above)
182              
183             =item Uploaders
184              
185             =item Provides
186              
187             =back
188              
189             =cut
190              
191             our %comma_separated = map(
192             ( $_ => 1 ),
193             keys %dependency_list,
194             qw( Uploaders Provides ),
195             );
196              
197             sub is_comma_separated {
198             my( $self, $field ) = @_;
199              
200             $field =~ s/_/-/g;
201              
202             return exists $comma_separated{$field};
203             }
204              
205             =item get($field)
206              
207             Overrides the default get method from L with L's
208             FETCH.
209              
210             =cut
211              
212             sub get {
213             my( $self, $field ) = @_;
214              
215             $field =~ s/_/-/g;
216              
217             return $self->FETCH($field);
218             }
219              
220             =item set( $field, $value )
221              
222             Overrides the default set method from L with L's
223             STORE. In the process, converts I<$value> to an instance of the
224             L class if I<$field> is to contain dependency list (as
225             determined by the L method).
226              
227             =cut
228              
229             sub set {
230             my( $self, $field, $value ) = @_;
231              
232             chomp($value);
233              
234             $field =~ s/_/-/g;
235              
236             $value = Debian::Dependencies->new($value)
237             if not ref($value) and $self->is_dependency_list($field);
238              
239             $value = Debian::Control::Stanza::CommaSeparated->new($value)
240             if not ref($value) and $self->is_comma_separated($field);
241              
242             return $self->STORE( $field, $value );
243             }
244              
245             =item as_string([$width])
246              
247             Returns a string representation of the object. Ready to be printed into a
248             real F file. Used as a stringification operator.
249              
250             Fields that are comma-separated use one line per item, except if they are like
251             C<${some:Field}>, in which case they are wrapped at I<$width>th column.
252             I<$width> defaults to 80.
253              
254             =cut
255              
256             use Text::Wrap ();
257              
258             sub as_string
259             {
260             my ( $self, $width ) = @_;
261             $width //= 80;
262              
263             my @lines;
264              
265             $self->Reorder( map{ ( my $s = $_ ) =~ s/_/-/g; $s } $self->fields );
266              
267             for my $k ( $self->Keys ) {
268             # We don't' want the internal fields showing in the output
269             next if $k =~ /^-/; # _ in field names is replaced with dashes
270             my $v = $self->FETCH($k);
271             next unless defined($v);
272             next if $self->is_dependency_list($k) and "$v" eq "";
273             next if $self->is_comma_separated($k) and "$v" eq "";
274              
275             my $line;
276              
277             if ( $self->is_comma_separated($k) ) {
278             # FIXME: this relies on $v being sorted
279             my ( @pre_dollar, @dollar, @post_dollar );
280             for ( @$v ) {
281             if ( /^\$\{.+}$/ ) {
282             push @dollar, $_;
283             }
284             elsif (@dollar) {
285             push @post_dollar, $_;
286             }
287             else {
288             push @pre_dollar, $_;
289             }
290             }
291              
292             if ( @pre_dollar ) {
293             $line = "$k: " . join( ",\n ", @pre_dollar );
294             local $Text::Warp::break = qr/, /;
295             local $Text::Warp::columns = $width;
296             local $Text::Wrap::separator = ",\n";
297             local $Text::Wrap::huge = 'overflow';
298             $line .= Text::Wrap::wrap( ' ', ' ', join( ', ', @dollar ) );
299             }
300             else {
301             local $Text::Warp::break = qr/, /;
302             local $Text::Warp::columns = $width;
303             local $Text::Wrap::separator = ",\n";
304             local $Text::Wrap::huge = 'overflow';
305             $line
306             = Text::Wrap::wrap( "$k: ", ' ', join( ', ', @dollar ) );
307             }
308              
309             $line = join( ",\n ", $line, @post_dollar );
310             }
311             else {
312             $line = "$k: $v";
313             }
314              
315             push @lines, $line if $line;
316             }
317              
318             return join( "\n", @lines ) . "\n";
319             }
320              
321             =back
322              
323             =head1 COPYRIGHT & LICENSE
324              
325             Copyright (C) 2009 Damyan Ivanov L
326              
327             This program is free software; you can redistribute it and/or modify it under
328             the terms of the GNU General Public License version 2 as published by the Free
329             Software Foundation.
330              
331             This program is distributed in the hope that it will be useful, but WITHOUT ANY
332             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
333             PARTICULAR PURPOSE.
334              
335             =cut
336              
337             1;