File Coverage

blib/lib/WWW/FMyLife.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package WWW::FMyLife;
2              
3 9     9   46589 use Moose;
  0            
  0            
4             use XML::Simple;
5             use LWP::UserAgent;
6             use WWW::FMyLife::Item;
7              
8             our $VERSION = '0.15';
9              
10             has 'username' => ( is => 'rw', isa => 'Str' );
11             has 'password' => ( is => 'rw', isa => 'Str' );
12              
13             has 'language' => ( is => 'rw', isa => 'Str', default => 'en' );
14             has 'token' => ( is => 'rw', isa => 'Str', default => q{} );
15             has 'key' => ( is => 'rw', isa => 'Str', default => 'readonly' );
16              
17             # XXX: is there a point to this? is this wannabe caching?
18             has 'pages' => ( is => 'rw', isa => 'Int' );
19              
20             has 'api_url' => (
21             is => 'rw',
22             isa => 'Str',
23             default => 'http://api.betacie.com',
24             );
25              
26             has 'module_error' => (
27             is => 'rw',
28             isa => 'Str',
29             clearer => 'clear_module_error',
30             );
31              
32             has 'fml_errors' => (
33             is => 'rw',
34             isa => 'ArrayRef[Str]',
35             clearer => 'clear_fml_errors',
36             );
37              
38             has 'error' => (
39             is => 'rw',
40             isa => 'Bool',
41             default => 0,
42             );
43              
44             has 'agent' => (
45             is => 'rw',
46             isa => 'Object',
47             default => sub { LWP::UserAgent->new(); },
48             );
49              
50             # Credentials sub: sets username and password as an array
51             sub credentials {
52             my ( $self, $user, $pass ) = @_;
53             $self->username ( $user );
54             $self->password ( $pass );
55              
56             return;
57             }
58              
59             sub top {
60             my ( $self, $opts ) = @_;
61             my @items = $self->_parse_options( $opts, 'top' );
62             return @items;
63             }
64              
65             sub top_day {
66             my ( $self, $opts ) = @_;
67             my @items = $self->_parse_options( $opts, 'top_day' );
68             return @items;
69             }
70              
71             sub top_week {
72             my ( $self, $opts ) = @_;
73             my @items = $self->_parse_options( $opts, 'top_week' );
74             return @items;
75             }
76              
77             sub top_month {
78             my ( $self, $opts ) = @_;
79             my @items = $self->_parse_options( $opts, 'top_month' );
80             return @items;
81             }
82              
83             sub flop {
84             my ( $self, $opts ) = @_;
85             my @items = $self->_parse_options( $opts, 'flop' );
86             return @items;
87             }
88              
89             sub flop_day {
90             my ( $self, $opts ) = @_;
91             my @items = $self->_parse_options( $opts, 'flop_day' );
92             return @items;
93             }
94              
95             sub flop_week {
96             my ( $self, $opts ) = @_;
97             my @items = $self->_parse_options( $opts, 'flop_week' );
98             return @items;
99             }
100              
101             sub flop_month {
102             my ( $self, $opts ) = @_;
103             my @items = $self->_parse_options( $opts, 'flop_month' );
104             return @items;
105             }
106              
107             sub last {
108             my ( $self, $opts ) = @_;
109             my $type = 'last';
110              
111             if ( ref $opts eq 'HASH' && $opts->{'category'} ) {
112             $type = $opts->{'category'};
113             }
114              
115             my @items = $self->_parse_options( $opts, $type );
116             return @items;
117             }
118              
119             sub get_id {
120             my ( $self, $id, $opts ) = @_;
121             $opts->{'page'} = '/nocomment';
122             my @items = $self->_parse_options( $opts, $id );
123             return @items;
124             }
125              
126             sub random {
127             my $self = shift;
128             my $xml = $self->_fetch_data('/view/random');
129             my $item = $self->_parse_item_as_object($xml);
130             return $item;
131             }
132              
133             sub _parse_options {
134             my ( $self, $opts, $add_url ) = @_;
135             my ( $as, $page );
136              
137             if ( ref $opts eq 'HASH' ) {
138             $as = $opts->{'as'};
139             $page = $opts->{'page'};
140             } else {
141             $page = $opts;
142             }
143              
144             $as ||= 'object';
145             $page ||= q{};
146              
147             my %types = (
148             object => sub { return $self->_parse_items_as_object(@_) },
149             text => sub { return $self->_parse_items_as_text (@_) },
150             data => sub { return $self->_parse_items_as_data (@_) },
151             );
152              
153             my $xml = $self->_fetch_data("/view/$add_url/$page");
154              
155             $xml || return;
156              
157             if ( my $id = $xml->{'items'}{'item'}{'id'} ) {
158             $xml->{'items'}{'item'} = { $id => $xml{'items'}{'item'} };
159             $xml->{'pages'} = 1;
160             }
161              
162             $self->pages( $xml->{'pages'} );
163              
164             my @items = $types{$as}->($xml);
165              
166             return @items;
167             }
168              
169             sub _fetch_data {
170             my ( $self, $add_to_url ) = @_;
171              
172             my $res = $self->agent->post(
173             $self->api_url . $add_to_url, {
174             key => $self->key,
175             language => $self->language,
176             },
177             );
178              
179             $self->error(0);
180             $self->clear_fml_errors;
181             $self->clear_module_error;
182              
183             if ( ! $res->is_success ) {
184             $self->error(1);
185             $self->module_error( $res->status_line );
186             return;
187             }
188              
189             my $xml = XMLin( $res->decoded_content );
190              
191             if ( my $raw_errors = $xml->{'errors'}->{'error'} ) {
192             my $array_errors =
193             ref $raw_errors eq 'ARRAY' ? $raw_errors : [ $raw_errors ];
194              
195             $self->error(1);
196             $self->fml_errors($array_errors);
197             return;
198             }
199              
200             return $xml;
201             }
202              
203             sub _parse_item_as_object {
204             # this parses a single item
205             my ( $self, $xml ) = @_;
206              
207             my %item_data = %{ $xml->{'items'}{'item'} };
208             my $item = WWW::FMyLife::Item->new();
209              
210             foreach my $attr ( keys %item_data ) {
211             $item->$attr( $item_data{$attr} );
212             }
213              
214             return $item;
215             }
216              
217             sub _parse_items_as_object {
218             # this parses multiple items
219             my ( $self, $xml ) = @_;
220             my @items;
221              
222             while ( my ( $id, $item_data ) = each %{ $xml->{'items'}{'item'} } ) {
223             my $item = WWW::FMyLife::Item->new(
224             id => $id,
225             );
226              
227             foreach my $attr ( keys %{$item_data} ) {
228             $item->$attr( $item_data->{$attr} );
229             }
230              
231             push @items, $item;
232             }
233              
234             return @items;
235             }
236              
237             sub _parse_items_as_text {
238             my ( $self, $xml ) = @_;
239             my @items = map { $_->{'text'} } values %{ $xml->{'items'}{'item'} };
240             return @items;
241             }
242              
243             sub _parse_items_as_data {
244             my ( $self, $xml ) = @_;
245             my $itemsref = $xml->{'items'}{'item'};
246             my @items = map +{ $_ => $itemsref->{$_} }, keys %{$itemsref};
247             return @items;
248             }
249              
250             no Moose;
251             __PACKAGE__->meta->make_immutable;
252              
253             1;
254              
255             __END__
256              
257             =head1 NAME
258              
259             WWW::FMyLife - Obtain FMyLife.com anecdotes via API
260              
261             =head1 VERSION
262              
263             Version 0.15
264              
265             =head1 SYNOPSIS
266              
267             THIS MODULE IS STILL UNDER INITIAL DEVELOPMENT! BE WARNED!
268              
269             use WWW::FMyLife;
270              
271             my $fml = WWW::FMyLife->new();
272             print map { "Items: $_\n" } $fml->last( { as => text' } );
273              
274             =head1 DESCRIPTION
275              
276             This module fetches FMyLife.com (FML) anecdotes, comments, votes and more via API, comfortably and in an extensible manner.
277              
278             my @items = $fml->top_daily();
279             foreach my $item (@items) {
280             my $item_id = $item->id;
281             my $item_content = $item->content;
282             print "[$item_id] $item_content\n";
283             }
284              
285             print $fml->random()->text, "\n";
286             ...
287              
288             =head1 EXPORT
289              
290             This module exports nothing.
291              
292             =head1 SUBROUTINES/METHODS
293              
294             =head2 last()
295              
296             Fetches the last quotes. Can accept a hashref that indicates the formatting:
297              
298             # returns an array of WWW::FMyLife::Item objects
299             $fml->last();
300              
301             # or more explicitly
302             $fml->last( { as => 'object' } ); # same as above
303             $fml->last( { as => 'text' } ); # returns an array of text anecdotes
304             $fml->last( { as => 'data' } ); # returns an array of hashes of anecdotes
305              
306             You can also specify which page you want:
307              
308             # return 1st page
309             my @last = fml->last();
310              
311             # return 5th page
312             my @last = $fml->last(5);
313              
314             # same
315             my @last = $fml->last( { page => 5 } );
316              
317             And options can be mixed:
318              
319             my @not_so_last = $fml->last( { as => 'text', page => 50 } );
320              
321             =head2 random
322              
323             This method gets a single random quote as an object.
324              
325             =head2 top
326              
327             This method works the same as the last() method, only it fetches the top quotes.
328              
329             This method, as for its variations, can format as an object, text or data.
330              
331             =head2 top_day
332              
333             This method works the same as the last() method, only it fetches the top quotes.
334              
335             This specific variant fetches the top anecdotes from the last day.
336              
337             =head2 top_week
338              
339             This method works the same as the last() method, only it fetches the top quotes.
340              
341             This specific variant fetches the top anecdotes from the last week.
342              
343             =head2 top_month
344              
345             This method works the same as the last() method, only it fetches the top quotes.
346              
347             This specific variant fetches the top anecdotes from the last month.
348              
349             =head2 flop
350              
351             Fetches the flop quotes.
352              
353             This method, as for its variations, can format as an object, text or data.
354              
355             =head2 flop_day
356              
357             Fetches the flop quotes of the day.
358              
359             =head2 flop_week
360              
361             Fetches the flop quotes of the week.
362              
363             =head2 flop_month
364              
365             Fetches the flop quotes of the month.
366              
367             =head2 credentials( $username, $password ) (NOT YET FULLY IMPLEMENTED)
368              
369             WARNING: THIS HAS NOT YET BEEN IMPLEMENTED.
370              
371             THE TESTS HAVE BEEN DISABLED FOR NOW, PLEASE WAIT FOR A MORE ADVANCED VERSION.
372              
373             Sets credentials for members.
374              
375             $fml->credentials( 'foo', 'bar' );
376              
377             # same thing
378             $fml->username('foo');
379             $fml->password('bar');
380              
381             =head1 AUTHOR
382              
383             Sawyer X (XSAWYERX), C<< <xsawyerx at cpan.org> >>
384              
385             Tamir Lousky (TLOUSKY), C<< <tlousky at cpan.org> >>
386              
387             =head1 DEPENDENCIES
388              
389             L<Moose>
390              
391             L<XML::Simple>
392              
393             L<LWP::UserAgent>
394              
395             =head1 BUGS AND LIMITATIONS
396              
397             Please report any bugs or feature requests to C<bug-www-fmylife at rt.cpan.org>, or through
398             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=WWW-FMyLife>.
399              
400             You can also use the Issues Tracker on Github @ L<http://github.com/xsawyerx/www-fmylife/issues>.
401              
402             =head1 SUPPORT
403              
404             You can find documentation for this module with the perldoc command.
405              
406             perldoc WWW::FMyLife
407              
408             You can also look for information at:
409              
410             =over 4
411              
412             =item * Our Github!
413              
414             L<http://github.com/xsawyerx/www-fmylife/tree/master>
415              
416             =item * RT: CPAN's request tracker
417              
418             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=WWW-FMyLife>
419              
420             =item * AnnoCPAN: Annotated CPAN documentation
421              
422             L<http://annocpan.org/dist/WWW-FMyLife>
423              
424             =item * CPAN Ratings
425              
426             L<http://cpanratings.perl.org/d/WWW-FMyLife>
427              
428             =item * Search CPAN
429              
430             L<http://search.cpan.org/dist/WWW-FMyLife/>
431              
432             =item * FML (FMyLife)
433              
434             L<http://www.fmylife.com>
435              
436             =back
437              
438             =head1 SEE ALSO
439              
440             =over 4
441              
442             =item * L<WWW::VieDeMerde>
443              
444             Apparently supports more options right now. Mainly for French version but seems to support English as well.
445              
446             =back
447              
448             =head1 LICENSE AND COPYRIGHT
449              
450             Copyright 2010 Sawyer X, Tamir Lousky.
451              
452             This program is free software; you can redistribute it and/or modify it
453             under the terms of either: the GNU General Public License as published
454             by the Free Software Foundation; or the Artistic License.
455              
456             See http://dev.perl.org/licenses/ for more information.
457