File Coverage

blib/lib/WebService/Audioscrobbler/Base.pm
Criterion Covered Total %
statement 18 80 22.5
branch 0 24 0.0
condition 0 3 0.0
subroutine 6 14 42.8
pod 7 7 100.0
total 31 128 24.2


line stmt bran cond sub pod time code
1             package WebService::Audioscrobbler::Base;
2 1     1   5 use warnings FATAL => 'all';
  1         2  
  1         36  
3 1     1   5 use strict;
  1         1  
  1         23  
4 1     1   5 use CLASS;
  1         2  
  1         4  
5            
6 1     1   37 use base 'Class::Data::Accessor';
  1         2  
  1         128  
7 1     1   5 use base 'Class::Accessor::Fast';
  1         1  
  1         74  
8            
9             require URI;
10             require URI::Escape;
11            
12 1     1   6 use WebService::Audioscrobbler;
  1         1  
  1         11  
13            
14             =head1 NAME
15            
16             WebService::Audioscrobbler::Base - An object-oriented interface to the Audioscrobbler WebService API
17            
18             =cut
19            
20             our $VERSION = '0.07';
21            
22             # artists related
23             CLASS->mk_classaccessor("artists_postfix" => "topartists.xml");
24             CLASS->mk_classaccessor("artists_class" => WebService::Audioscrobbler->artist_class );
25             CLASS->mk_classaccessor("artists_sort_field" => "count");
26            
27             # tracks related
28             CLASS->mk_classaccessor("tracks_postfix" => "toptracks.xml");
29             CLASS->mk_classaccessor("tracks_class" => WebService::Audioscrobbler->track_class );
30             CLASS->mk_classaccessor("tracks_sort_field" => "count");
31            
32             # tags related
33             CLASS->mk_classaccessor("tags_postfix" => "toptags.xml");
34             CLASS->mk_classaccessor("tags_class" => WebService::Audioscrobbler->tag_class );
35             CLASS->mk_classaccessor("tags_sort_field" => "count");
36            
37             # object accessors
38             CLASS->mk_accessors(qw/data_fetcher/);
39            
40             =head1 SYNOPSIS
41            
42             This module implements the base class for all other L modules.
43            
44             package WebService::Audioscrobbler::Subclass;
45             use base 'WebService::Audioscrobbler::Base';
46            
47             ...
48            
49             my $self = WebService::Audioscrobbler::Subclass->new;
50            
51             # retrieves tracks
52             my @tracks = $self->tracks;
53            
54             # retrieves tags
55             my @tags = $self->tags;
56            
57             # retrieves arbitrary XML data as a hashref, using XML::Simple
58             my $data = $self->fetch_data('resource.xml');
59            
60            
61             =head1 METHODS
62            
63             =cut
64            
65             =head2 C
66            
67             Retrieves the tracks related to the current resource as available on Audioscrobbler's database.
68            
69             Returns either a list of tracks or a reference to an array of tracks when called
70             in list context or scalar context, respectively. The tracks are returned as
71             L objects by default.
72            
73             =cut
74            
75             sub tracks {
76 0     0 1   my $self = shift;
77            
78 0           my $data = $self->fetch_data($self->tracks_postfix);
79            
80 0           my @tracks;
81            
82 0 0         if (ref $data->{track} eq 'HASH') {
83 0           my $tracks = $data->{track};
84 0           my $sort_field = $self->tracks_sort_field;
85            
86 0           @tracks = map {
87 0           my $title = $_;
88            
89 0           my $info = $tracks->{$title};
90 0           $info->{name} = $title;
91            
92 0 0         if (defined $info->{artist}) {
    0          
93 0           $info->{artist}->{data_fetcher} = $self->data_fetcher;
94 0           $info->{artist} = $self->artists_class->new($info->{artist});
95             }
96             elsif ($self->isa($self->artists_class)) {
97 0           $info->{artist} = $self;
98             }
99             else {
100 0           $self->croak("Couldn't determine artist for track");
101             }
102            
103 0           $info->{data_fetcher} = $self->data_fetcher;
104            
105 0           $self->tracks_class->new($info);
106            
107 0           } sort {$tracks->{$b}->{$sort_field} <=> $tracks->{$a}->{$sort_field}} keys %$tracks;
108             }
109            
110 0 0         return wantarray ? @tracks : \@tracks;
111            
112             }
113            
114             =head2 C
115            
116             Retrieves the tags related to the current resource as available on Audioscrobbler's database.
117            
118             Returns either a list of tags or a reference to an array of tags when called
119             in list context or scalar context, respectively. The tags are returned as
120             L objects by default.
121            
122             =cut
123            
124             sub tags {
125 0     0 1   my $self = shift;
126            
127 0           my $data = $self->fetch_data($self->tags_postfix);
128            
129 0           my @tags;
130            
131 0 0         if (ref $data->{tag} eq 'HASH') {
132 0           my $tags = $data->{tag};
133            
134 0 0 0       if (exists $tags->{name} && !ref $tags->{name}) {
135 0           @tags = $self->_process_tag( $tags );
136             }
137             else {
138 0           my $sort_field = $self->tags_sort_field;
139 0           @tags = map {
140 0           $self->_process_tag( $tags->{ $_ }, $_ );
141 0           } sort {$tags->{$b}->{$sort_field} <=> $tags->{$a}->{$sort_field}} keys %$tags;
142             }
143             }
144            
145 0 0         return wantarray ? @tags : \@tags;
146            
147             }
148            
149             sub _process_tag {
150 0     0     my ($self, $info, $name) = @_;
151            
152 0 0         $info->{name} = $name if defined $name;
153            
154 0 0         die "no tag name" unless defined $info->{name};
155            
156 0           $info->{data_fetcher} = $self->data_fetcher;
157            
158 0           $self->tags_class->new($info);
159            
160             }
161            
162             =head2 C
163            
164             Retrieves the artists related to the current resource as available on Audioscrobbler's database.
165            
166             Returns either a list of artists or a reference to an array of artists when called
167             in list context or scalar context, respectively. The tags are returned as
168             L objects by default.
169            
170             =cut
171            
172             sub artists {
173 0     0 1   my $self = shift;
174            
175 0           my $data = $self->fetch_data($self->artists_postfix);
176            
177 0           my @artists;
178            
179 0 0         if (ref $data->{artist} eq 'HASH') {
180 0           my $artists = $data->{artist};
181 0           my $sort_field = $self->artists_sort_field;
182 0           @artists = map {
183 0           my $name = $_;
184            
185 0           my $info = $artists->{$name};
186 0           $info->{name} = $name;
187 0           $info->{data_fetcher} = $self->data_fetcher;
188            
189 0           $self->artists_class->new($info);
190            
191 0           } sort {$artists->{$b}->{$sort_field} <=> $artists->{$a}->{$sort_field}} keys %$artists;
192             }
193            
194 0 0         return wantarray ? @artists : \@artists;
195            
196             }
197            
198             =head2 C
199            
200             This method retrieves arbitrary data from this resource using the specified
201             C<$postfix>. This is accomplished by calling the C method of this
202             object's data fetcher object (usually an instance of L).
203            
204             =cut
205            
206             sub fetch_data {
207 0     0 1   my ($self, $postfix) = @_;
208            
209 0           my $uri = $self->resource_path->clone;
210 0           $uri->path_segments($uri->path_segments, $postfix);
211            
212             # warn "\nFetching resource '$uri'\n";
213            
214 0           return $self->data_fetcher->fetch($uri);
215             }
216            
217             =head2 C
218            
219             This method must be overriden by classes which inherit from C. It should
220             return the relative resource URL which will be used for fetching it from
221             Audioscrobbler.
222            
223             =cut
224            
225             sub resource_path {
226 0     0 1   my $class = ref shift;
227 0           croak("$class must override the 'resource_path' method");
228             }
229            
230             =head2 C
231            
232             Helps classes which inherit from WebService::Audioscrobbler::Base to build
233             URI objects. Mainly used for keeping C code cleaner in those
234             classes.
235            
236             =cut
237            
238             sub uri_builder {
239 0     0 1   my ($self, @bits) = @_;
240 0           URI->new( join '/', $self->base_resource_path, map {URI::Escape::uri_escape($_)} @bits );
  0            
241             }
242            
243             =head2 C
244            
245             Shortcut for C which can be called as a method.
246            
247             =cut
248            
249             sub croak {
250 0 0   0 1   shift if $_[0]->isa(CLASS);
251 0           require Carp;
252 0           Carp::croak(@_);
253             }
254            
255             =head1 AUTHOR
256            
257             Nilson Santos Figueiredo Júnior, C<< >>
258            
259             =head1 COPYRIGHT & LICENSE
260            
261             Copyright 2006-2007 Nilson Santos Figueiredo Júnior, all rights reserved.
262            
263             This program is free software; you can redistribute it and/or modify it
264             under the same terms as Perl itself.
265            
266             =cut
267            
268             1; # End of WebService::Audioscrobbler::Base