File Coverage

blib/lib/Weewar.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Weewar;
2 5     5   59158 use strict;
  5         11  
  5         186  
3 5     5   28 use warnings;
  5         9  
  5         124  
4              
5 5     5   29 use Carp;
  5         19  
  5         429  
6 5     5   8622 use LWP::UserAgent;
  5         402128  
  5         183  
7 5     5   8426 use XML::LibXML;
  0            
  0            
8              
9             use Weewar::User;
10             use Weewar::Game;
11             use Weewar::HQ;
12              
13             our $VERSION = '0.01';
14              
15             use Readonly;
16             Readonly my $server => $ENV{WEEWAR_SERVER} || 'weewar.com';
17             Readonly my $base => $ENV{WEEWAR_BASE} || 'api1';
18              
19             =head1 NAME
20              
21             Weewar - get data from the weewar.com XML API
22              
23             =head1 SYNOPSIS
24              
25             use Weewar;
26              
27             # get all users
28             my @users = Weewar->all_users; # all active players on weewar
29              
30             # get a single user
31             my $me = Weewar->user('jrockway'); # one user only (as a Weewar::User)
32             my $me = Weewar::User->new({ name => 'jrockway }); # lazy-loaded
33              
34             # get a game
35             my $game = Weewar->game('27056'); # get game (as a Weewar::Game)
36             my $game = Weewar::Game->new({ id => '27056' });
37            
38             # access headquarters
39             my $hq = Weewar->hq('jrockway' => $jrockways_api_key);
40             my $hq = Weewar::HQ->new({ user => 'jrockway',
41             key => $jrockways_api_key,
42             });
43              
44             =head1 DESCRIPTION
45              
46             This module lets you interact with the
47             (L) API. See
48             L, L, and L for details about
49             what data you can get from the API.
50              
51             =head1 METHODS
52              
53             Right now, everything is a class method since the weewar API is public
54             for everything except the HQ (and no state needs to be kept between
55             requests). If this changes, then this API will change a bit.
56              
57             =cut
58              
59             { package Weewar::UA;
60             use base 'LWP::UserAgent';
61             sub new {
62             my ($class, $args) = @_;
63             $args ||= {};
64             bless $args => $class;
65             }
66             sub get_basic_credentials {
67             my $self = shift;
68             return unless $self->{username};
69             return (map {$self->{$_}} qw/username password/);
70             }
71             }
72              
73             # separate method so that WeewarTest can override the HTTP part
74             sub _get {
75             my ($class, $path, $args) = @_;
76            
77             my $ua = Weewar::UA->new($args);
78             my $res = $ua->get("http://$server/$base/$path");
79            
80             croak 'request error: '. $res->status_line if !$res->is_success;
81             return $res->decoded_content;
82             }
83              
84             sub _request {
85             my ($class, $path, $args) = @_;
86             my $content = $class->_get($path, $args);
87             my $parser = XML::LibXML->new;
88             return $parser->parse_string($content);
89             }
90              
91             =head2 all_users
92              
93             Return a list of all active Weewar users as L objects.
94             The objects are loaded lazily, so this method only causes one request
95             to be sent to the server. When you start accessing the returned
96             children, they will be populated on-demand from the server.
97              
98             An exception will be thrown if something goes wrong.
99              
100             =cut
101              
102             sub all_users {
103             my $class = shift;
104             my $doc = $class->_request('users/all');
105             my @raw_users = $doc->getElementsByTagName('user');
106            
107             my @users;
108             foreach my $user (@raw_users){
109             my $def;
110             $def->{$_} = $user->getAttributeNode($_)->value for qw/name id rating/;
111             $def->{points} = $def->{rating}; # API uses 2 names for the same thing
112             push @users, Weewar::User->new($def);
113             }
114             return @users;
115             }
116              
117             =head2 user($username)
118              
119             Returns a C object representing C<$username>. If there is
120             no user by that name, and exception is thrown.
121              
122             =cut
123              
124             sub user {
125             my $class = shift;
126             my $username = shift;
127             my $user = Weewar::User->new({ name => $username });
128             $user->draws; # force the object to be populated
129             return $user;
130             }
131              
132             =head2 game($id)
133              
134             Returns a C object representing the game with id C<$id>. If
135             there is no game with that id, an exception is thrown.
136              
137             =cut
138              
139             sub game {
140             my $class = shift;
141             my $gameid = shift;
142             my $game = Weewar::Game->new({ id => $gameid });
143             $game->name; # force the object to be populated
144             return $game;
145             }
146              
147             =head2 hq($username => $apikey)
148              
149             Returns a C object representing C<$username>'s
150             "headquarters". If there is an error getting the data (bad API key,
151             etc.), an exception is thrown.
152              
153             =cut
154              
155             sub hq {
156             my $class = shift;
157             my ($user, $key) = @_;
158             my $hq = Weewar::HQ->new({ key => $key, user => $user });
159             return $hq;
160             }
161              
162             =head1 ENVIRONMENT
163              
164             You can use different weewar servers by changing these environment
165             variables. I doubt there are other weewar servers that speak this
166             API, though.
167              
168             =over 4
169              
170             =item WEEWAR_SERVER
171              
172             The hostname of the Weewar server, defaulting to C
173              
174             =item WEEWAR_BASE
175              
176             The base URL of the API, defaulting to C.
177              
178             =back
179              
180             =head1 BUGS
181              
182             If the Weewar API changes, this module will need an update. Let me
183             know if something is broken so I can fix it.
184              
185             The combination of Weewar's odd XML, C, and the fact that
186             I had very little sleep before writing this makes for some very ugly
187             code. Feel free to clean it up and send me a patch.
188              
189             Bugs should be reported through RT, but you can email me directly too.
190              
191             =head1 AUTHOR
192              
193             Jonathan Rockway C<< >>
194              
195             =head1 COPYRIGHT
196              
197             This module is copyright (c) 2007 Jonathan Rockway.
198              
199             You can distribute, modify, and use this module under the same terms
200             as Perl itself.
201              
202             =cut
203              
204             1;