File Coverage

blib/lib/Music/ABC/Archive.pm
Criterion Covered Total %
statement 138 159 86.7
branch 40 68 58.8
condition 8 15 53.3
subroutine 14 17 82.3
pod 8 11 72.7
total 208 270 77.0


line stmt bran cond sub pod time code
1             package Music::ABC::Archive;
2              
3 1     1   23905 use 5.008;
  1         4  
  1         39  
4 1     1   6 use strict;
  1         2  
  1         35  
5 1     1   5 use warnings;
  1         8  
  1         37  
6 1     1   6 use Carp ;
  1         2  
  1         192  
7              
8             require Exporter;
9              
10             our @ISA = qw(Exporter);
11              
12             our %EXPORT_TAGS = ( 'all' => [ qw(new parse openabc filename list_by_title get_song print_song_summary get_song_titles) ] );
13              
14             our @EXPORT_OK = qw(new parse openabc filename list_by_title get_song print_song_summary) ;
15             our @EXPORT = ( );
16              
17             our $VERSION = '0.02';
18              
19 1     1   911 use Music::ABC::Song ;
  1         2125  
  1         1770  
20              
21             my (@header_lines, %Song_objs, %Song_data, %Unique_display_name) ;
22              
23             sub new
24             {
25 1     1 1 533 my $class = shift ;
26 1         3 my $self = {} ;
27 1         2 my $filename = shift ;
28 1         2 $self->{FILENAME} = "" ;
29              
30 1 50       3 if(defined($filename)) {
31 1         3 $self->{FILENAME} = $filename ;
32             }
33              
34 1         2 bless ($self, $class) ;
35 1         6 $self->{Is_parsed} = 0 ;
36 1         2 $self->{File_is_open} = 0 ;
37 1         3 return $self ;
38             }
39              
40             sub abc_reset
41             {
42 0     0 0 0 my $self = shift ;
43 0         0 $self->{Is_parsed} = 0 ;
44 0         0 %Song_data = () ;
45 0         0 %Song_objs = () ;
46 0         0 %Unique_display_name = () ;
47             #close($self->{fh}) if $self->{File_is_open} ;
48             #$self->{File_is_open} = 0 ;
49             }
50              
51             sub filename
52             {
53 0     0 1 0 my $self = shift ;
54 0         0 my $newfilename = shift ;
55              
56 0 0       0 if($newfilename) {
57 0 0       0 if($newfilename ne $self->{FILENAME}) {
58 0         0 $self->{FILENAME} = $newfilename ;
59 0         0 $self->abc_reset() ;
60             }
61             }
62              
63 0         0 return $self->{FILENAME} ;
64             }
65              
66             sub openabc
67             {
68 1     1 1 6 my $self = shift ;
69 1         1 my $filename = shift ;
70 1         3 my $fh ;
71              
72 1 50       2 if(defined($filename)) {
73 1         3 $self->{FILENAME} = $filename ;
74             }
75              
76 1 50       3 close($self->{fh}) if $self->{File_is_open} ;
77 1         2 $self->{File_is_open} = 0 ;
78              
79 1 50       30 open($fh, "<$self->{FILENAME}") || return 0 ;
80 1         2 $self->{fh} = $fh ;
81 1         2 $self->{File_is_open} = 1 ;
82              
83 1         9 return 1 ;
84             }
85              
86             sub parse
87             {
88 1     1 1 2 my $self = shift ;
89 1 50       5 return if $self->{Is_parsed} ;
90              
91 1 50       8 $self->openabc() if !$self->{File_is_open} ;
92              
93 1         593 my $display_name ;
94 1         2 my $currpos = tell(${$self->{fh}}) ;
  1         4  
95 1         2 my $songnumber ;
96 1         2 my $type = "" ;
97 1         2 my $key = "" ;
98 1         2 my $meter = "" ;
99 1         1 my $currobj ;
100             my $songnum ;
101 1         4 my $fname = $self->{FILENAME} ;
102 1         2 my $in_song = 0 ;
103 1         2 my $in_songs = 0 ;
104 1         2 my $found_meter = 0 ;
105 1         1 my $found_type = 0 ;
106 1         2 my $fh = $self->{fh} ;
107              
108              
109 1         19 while (<$fh>) {
110             #print ;
111 29         38 chomp ;
112 29         39 s/\r// ;
113 29         46 s/\n// ;
114 29         68 my $text = $_ ;
115             #print "$t[0] $t[1]\n" ;
116              
117             ## 4 header types we need to explicity detect X,T,M and R
118 29 100       112 if (/^X\:/) {
    100          
    100          
    100          
119 2         8 my @t = split(':') ;
120 2 50       6 $t[1] = "" if(!defined($t[1])) ;
121 2         4 $t[1] =~ s/^\s+//; # trim leading whitespace
122 2         3 $t[1] =~ s/\s+$//; # trim trailing whitespace
123 2         5 $songnum = $t[1] + 0 ;
124 2         10 $Song_objs{$songnum} = Music::ABC::Song->new(archivename=>$fname, number=>$songnum) ;
125 2         115 $Song_objs{$songnum}->filepos($currpos) ;
126 2         12 $in_song = 0 ;
127             } elsif (/^T\:/) {
128 3         9 my @t = split(':') ;
129 3 50       9 $t[1] = "" if(!defined($t[1])) ;
130 3         6 $t[1] =~ s/^\s+//; # trim leading whitespace
131 3         7 $t[1] =~ s/\s+$//; # trim trailing whitespace
132 3         5 my $append = "" ;
133 3         5 my $name = $t[1] ;
134              
135              
136 3         5 my $display_name = $name . $append ;
137              
138 3         8 while (defined($Unique_display_name{$display_name})) {
139 0 0       0 if($append eq "") {
140 0         0 $append = 2 ;
141             } else {
142 0         0 $append++ ;
143             }
144 0         0 $display_name = $name . " (" . $append . ")" ;
145             }
146              
147 3         10 $Song_objs{$songnum}->display_name($display_name) ;
148              
149             # set the display_name in the unique hash so we can avoid
150             # future name collisions
151 3         20 $Unique_display_name{$display_name} = 1 ;
152              
153             } elsif (/^R\:/) {
154 2         7 my @t = split(':') ;
155 2 50       14 $t[1] = "" if(!defined($t[1])) ;
156 2         6 $type = $t[1] ;
157             } elsif (/^M\:/) {
158 2         7 my @t = split(':') ;
159 2 50       5 $t[1] = "" if(!defined($t[1])) ;
160 2         4 $meter = $t[1] ;
161             }
162              
163              
164 29 100       61 if(/^%/) {
165             # this line silently passes through, but
166             # isn't necessarily the start of the song
167 2 50       6 if(!$in_songs) {
168 2         6 push @header_lines, $_ ;
169              
170             }
171             }
172            
173 29 100       63 if($songnum) {
174 27 100       60 if (/^(.):/) {
175 18         49 my ($code, @v) = split(':') ;
176 18         35 my $text = join ":", @v ;
177 18 100 66     98 if($in_song || !($1 =~/[MR]/)) {
178 14 50       59 $Song_objs{$songnum}->header($1, $text) if($1 ne "|") ;
179             }
180             } else {
181 9 100       18 if(!$in_song) {
182             # type (R) and meter (M) headers are inherited from
183             # any previous occurences, or the ones we found in this song
184             # so we set them, and output them here just before the song text ;
185 2         7 $Song_objs{$songnum}->header("R", $type) ;
186 2         25 $Song_objs{$songnum}->header("M", $meter) ;
187 2         23 $Song_objs{$songnum}->type($type) ;
188 2         16 $Song_objs{$songnum}->meter($meter) ;
189             }
190 9         17 $in_song = 1 ;
191 9         11 $in_songs = 1 ;
192             }
193              
194 27         237 $Song_objs{$songnum}->text($_) ;
195             }
196              
197 29         242 $currpos = tell($self->{fh}) ;
198             }
199              
200 1         4 $self->{Is_parsed} = 1 ;
201             }
202              
203             sub get_song
204             {
205 1     1 1 733 my $self = shift ;
206 1         2 my $songnum = shift ;
207 1   50     7 my $no_headers = @_ || 0 ;
208 1         2 my @data ;
209              
210 1         2 eval {
211 1 50       6 $self->parse() if(!$self->{Is_parsed}) ;
212              
213 1         3 foreach(@{$Song_objs{$songnum}->text()}) {
  1         5  
214 15 50 66     69 next if /^[A-Z]:/ && $no_headers ;
215 15 50 33     39 next if /^[a-z]:/ && $no_headers ;
216 15         24 push (@data, $_) ;
217             }
218             } ;
219              
220 1 50       4 croak "get_song failed" if ($@) ;
221              
222 1         11 return @data ;
223             }
224              
225             sub get_archive_header_lines
226             {
227 1     1 1 478 my $self = shift ;
228 1         2 eval {
229 1 50       4 $self->parse() if(!$self->{Is_parsed}) ;
230             } ;
231              
232 1 50       4 croak "get_archive_header_lines failed" if ($@) ;
233              
234             #print "Returning Header Lines:\n@header_lines\n" ;
235              
236 1         5 return @header_lines ;
237             }
238              
239             sub print_song_summary
240             {
241 2     2 1 769 my $self = shift ;
242 2         4 my $songnum = shift ;
243 2   100     10 my $use_html_tags = shift || 0 ;
244 2         4 my @data ;
245              
246 2 100       11 $self->parse() if(!$self->{Is_parsed}) ;
247              
248 2         4 my $sr = $Song_objs{$songnum} ;
249              
250 2         7 return $sr->get_song_summary($use_html_tags) ;
251             }
252              
253             sub by_name
254             {
255 1     1 0 3 my $hrefa = $Song_objs{$a} ;
256 1         2 my $hrefb = $Song_objs{$b} ;
257              
258 1         4 return $hrefa->display_name() cmp $hrefb->display_name() ;
259             }
260              
261              
262             sub list_by_title
263             {
264 1     1 1 462 my $self = shift ;
265 1         3 my @data ;
266              
267 1 50       4 $self->parse() if(!$self->{Is_parsed}) ;
268              
269 1         9 foreach my $songnum (sort by_name keys %Song_objs) {
270 2         37 push (@data, [$Song_objs{$songnum}->display_name(),
271             $songnum,
272             $Song_objs{$songnum}->type(),
273             $Song_objs{$songnum}->meter(),
274             $Song_objs{$songnum}->key(),
275             $Song_objs{$songnum}->titles(),
276             ]) ;
277             }
278              
279 1         20 return @data ;
280             }
281              
282             sub get_song_titles
283             {
284 0     0 0 0 my $self = shift ;
285 0   0     0 my $songnum = shift || return undef ;
286              
287 0 0       0 $self->parse() if(!$self->{Is_parsed}) ;
288              
289 0         0 return @{$Song_objs{$songnum}->titles()} ;
  0         0  
290             }
291              
292             sub DESTROY
293             {
294 1     1   466 my $self = shift ;
295 1 50       144 close($self->{fh}) if $self->{File_is_open} ;
296             }
297              
298             1;
299             __END__