File Coverage

blib/lib/WWW/SourceForge.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package WWW::SourceForge;
2 5     5   21926 use strict;
  5         9  
  5         257  
3 5     5   5016 use LWP::Simple qw(get);
  5         565588  
  5         51  
4 5     5   5653 use JSON::Parse;
  5         4714  
  5         239  
5 5     5   2254 use XML::Feed;
  0            
  0            
6             use File::HomeDir;
7              
8             our $VERSION = '0.70'; # This is the overall version for the entire
9             # package, so should probably be updated even when the other modules are
10             # touched.
11              
12             =head2 new
13              
14             Usage : my $sfapi = new WWW::SourceForge;
15             Returns : WWW::SourceForge object
16              
17             Optionally pass an 'api' argument to select one of the other APIs.
18              
19             my $download_api = WWW::SourceForge->new( api => 'download' );
20              
21             See https://sourceforge.net/p/forge/documentation/Download%20Stats%20API/
22              
23             =cut
24              
25             sub new {
26             my ( $class, %parameters ) = @_;
27              
28             my $api = $parameters{api} || 'data';
29             my $api_url;
30              
31             # TODO: This stuff made sense when I wrote it, but until there's a
32             # single unified API, this is just confusing. Need to nuke this bit
33             if ( $api eq 'download' ) {
34             $api_url = 'http://sourceforge.net/projects';
35             } else {
36             $api_url = 'http://sourceforge.net/api';
37             }
38              
39             my $self = bless(
40             {
41             api_url => $api_url,
42             api => $api,
43             },
44             ref($class) || $class
45             );
46              
47             return $self;
48             }
49              
50             =head2 call
51              
52             Usage : my $json = $sfapi->call(
53             method => whatever,
54             arg1 => 'value',
55             arg2 => 'another value',
56             format => 'rss',
57             );
58             Returns : Hashref, containing a bunch of data. Format defaults to
59             'json', but in some cases, you'll want to force rss because that's
60             how the return is available. Will try to make this smarter
61             eventually.
62              
63             Calls a particular method in the SourceForge API. Other args are passed
64             as args to that call.
65              
66             =cut
67              
68             sub call {
69             my $self = shift;
70             my %args = @_;
71              
72             my $r = {};
73             my $url;
74             my $format;
75              
76             if ( defined( $args{method} ) && ( $args{ method } eq 'proj_activity' ) ) {
77             my $project = $args{ project };
78             $url =
79             'http://sourceforge.net/export/rss2_keepsake.php?group_id=' .
80             $project->id();
81             $format = 'rss';
82             }
83              
84             # Download API, documented at
85             # https://sourceforge.net/p/forge/documentation/Download%20Stats%20API/
86             elsif ( $self->{api} eq 'download' ) {
87              
88             # TODO: Default start date, end date (last 7 days, perhaps?)
89              
90             # TODO: API allows specification of subdirs of the files
91             # hierarchy, and we don't allow that yet here.
92              
93             $url =
94             $self->{api_url} . '/'
95             . $args{project}
96             . '/files/stats/json?start_date=' . $args{start_date}
97             . '&end_date=' . $args{end_date};
98              
99             $format = 'json';
100              
101             # Data API, documented at
102             # https://sourceforge.net/p/forge/documentation/API/
103             } else {
104              
105             # HACK
106             # If a full URI is provided, use that
107             if ( $args{uri} ) {
108             $format = $args{format} || 'json';
109             $url = $self->{api_url} . $args{uri};
110             } else {
111              
112             my $method = $args{method} || return $r;
113             delete( $args{method} );
114              
115             $format = $args{format} || 'json';
116             delete( $args{format} );
117              
118             $url = $self->{api_url} . '/' . $method;
119             # $url .= '/' . join('/',@args);
120             foreach my $a ( keys %args ) {
121             $url .= '/' . $a . '/' . $args{$a};
122             }
123              
124             # Format defaults to 'json'
125             $url .= '/' . $format;
126             }
127             }
128              
129             if ( $format eq 'rss' ) {
130             $r = { entries => [] };
131              
132             my $feed;
133             eval { $feed = XML::Feed->parse( URI->new($url) ) };
134             if ($@) {
135             warn $@;
136             return $r;
137             }
138             {
139             no warnings 'all';
140             if ( $feed && $feed->entries ) {
141             for my $entry ( $feed->entries ) {
142             push @{ $r->{entries} }, $entry;
143             }
144             } else {
145             return { entries => [] };
146             }
147             }
148             } else {
149             my $json = get($url);
150             eval { $r = JSON::Parse::json_to_perl($json); };
151             if ( $@ ) {
152             warn $@;
153             return { entries => [] };
154             }
155             }
156             return $r;
157             }
158              
159             # Loads a config from ~/.sourceforge
160             sub get_config {
161             my $conf = File::HomeDir->my_home() . "/.sourceforge";
162             my %config = ();
163              
164             if ( -e $conf ) {
165             open my $C, "<$conf" or die "Couldn't open $conf";
166             my @conf = <$C>;
167             close $C;
168              
169             foreach my $line (@conf) {
170             chomp $line;
171             next if $line =~ m/^#/;
172              
173             my ( $var, $val ) = split /\s+/, $line;
174             next unless $val;
175             $config{$var} = $val;
176             }
177             }
178             return %config;
179             }
180              
181             =head1 NAME
182              
183             WWW::SourceForge - Interface to SourceForge's APIs - http://sourceforge.net/p/forge/documentation/API/ and https://sourceforge.net/p/forge/documentation/Download%20Stats%20API/
184              
185             =head1 SYNOPSIS
186              
187             Usually you'll use this via WWW::SourceForge::Project and
188             WWW::SourceForge::User rather than using this directly.
189              
190             =head1 DESCRIPTION
191              
192             Implements a Perl interface to the SourceForge API, documented here:
193             http://sourceforge.net/p/forge/documentation/API/ and here:
194             https://sourceforge.net/p/forge/documentation/Download%20Stats%20API/
195              
196             =head1 USAGE
197              
198             use WWW::SourceForge;
199             my $sfapi = new WWW::SourceForge;
200              
201             See WWW::SourceForge::User and WWW::SourceForge::Project for details.
202              
203             =head1 BUGS
204              
205             None
206              
207             =head1 SUPPORT
208              
209             http://sourceforge.net/p/sfprojecttools/tickets/
210              
211             =head1 AUTHOR
212              
213             Rich Bowen
214             CPAN ID: RBOW
215             SourceForge
216             rbowen@sourceforge.net
217             http://sf.net
218              
219             =head1 COPYRIGHT
220              
221             This program is free software; you can redistribute
222             it and/or modify it under the same terms as Perl itself.
223              
224             The full text of the license can be found in the
225             LICENSE file included with this module.
226              
227              
228             =head1 SEE ALSO
229              
230             perl(1).
231              
232             =cut
233              
234             #################### main pod documentation end ###################
235              
236              
237             1;
238