File Coverage

blib/lib/WWW/IRail/API.pm
Criterion Covered Total %
statement 12 14 85.7
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package WWW::IRail::API;
2             BEGIN {
3 2     2   110456 $WWW::IRail::API::AUTHORITY = 'cpan:ESSELENS';
4             }
5             BEGIN {
6 2     2   42 $WWW::IRail::API::VERSION = '0.003';
7             }
8 2     2   18 use strict;
  2         5  
  2         76  
9 2     2   12 use warnings;
  2         3  
  2         90  
10 2     2   12 use Carp qw/croak/;
  2         6  
  2         249  
11 2     2   1227 use WWW::IRail::API::Stations;
  0            
  0            
12             use WWW::IRail::API::Connections;
13             use WWW::IRail::API::Liveboard;
14             use WWW::IRail::API::Vehicle;
15              
16             use parent 'Exporter';
17             our @EXPORT = qw/&irail/;
18              
19              
20             sub new {
21             my ($proto, $attr) = @_;
22             my $class = ref $proto || $proto;
23             my %attr = ( API => "v1",
24             dataType => 'perl',
25             client => 'LWP',
26             _cache => { stations => [],
27             connections => {},
28             liveboards => {},
29             vehicles => {},
30             timestamps => {}
31             },
32             ref $attr eq 'HASH' ? %{$attr} : @{$attr || []} );
33              
34              
35             eval "require WWW::IRail::API::Client::$attr{client}"; die $@ if $@;
36              
37             "WWW::IRail::API::Client::$attr{client}"->can('process')
38             or croak "unable to initialize ". __PACKAGE__ ."::Client::$attr{client} backend. ".
39             "Is the module loaded?";
40              
41             $attr{client} = "WWW::IRail::API::Client::$attr{client}"->new();
42              
43              
44             return bless {%attr}, $class;
45             }
46              
47              
48             sub lookup_stations {
49             my $self = shift;
50              
51             # auto dereference first argument from hashref to hash
52             my %opts = ref $_[0] eq 'HASH' ? %{$_[0]} : @_;
53              
54             # if the 2nd argumnet is a sub, use it as the callback, but only if the first was a {}
55             my $callback = ref $_[0] eq 'HASH' && ref $_[1] eq 'CODE' ? $_[1] : $opts{callback};
56              
57             # either the station or search parameter can be used to filter
58             my $re = $opts{station} || $opts{filter} || '.';
59              
60             # check the filter is a sub or match using default sub
61             my $search_cb = ref $opts{filter} eq 'CODE' ? $opts{filter} : sub { m/$re/i };
62              
63             my $http_req = WWW::IRail::API::Stations::make_request(\%opts);
64             my $http_res = $self->{client}->process($http_req, $callback);
65             my $response = WWW::IRail::API::Stations::parse_response( $http_res,
66             $opts{dataType} || $self->{dataType},
67             $search_cb );
68             return $response;
69             }
70              
71             sub lookup_connections {
72             my $self = shift;
73             my %opts = ref $_[0] ? %{$_[0]} : @_;
74              
75             my $callback = ref $_[1] eq 'CODE' ? $_[1] : $opts{callback};
76              
77             my $http_req = WWW::IRail::API::Connections::make_request(\%opts);
78             my $http_res = $self->{client}->process($http_req, $callback);
79             my $response = WWW::IRail::API::Connections::parse_response( $http_res,
80             $opts{dataType} || $self->{dataType});
81             return $response;
82             }
83              
84             sub lookup_liveboard {
85             my $self = shift;
86             my %opts = ref $_[0] ? %{$_[0]} : @_;
87              
88             my $callback = ref $_[1] eq 'CODE' ? $_[1] : $opts{callback};
89              
90             my $http_req = WWW::IRail::API::Liveboard::make_request(\%opts);
91             my $http_res = $self->{client}->process($http_req, $callback);
92             my $response = WWW::IRail::API::Liveboard::parse_response( $http_res,
93             $opts{dataType} || $self->{dataType});
94             return $response;
95             }
96              
97             sub lookup_vehicle {
98             my $self = shift;
99             my %opts = ref $_[0] ? %{$_[0]} : @_;
100              
101             my $callback = ref $_[1] eq 'CODE' ? $_[1] : $opts{callback};
102              
103             my $http_req = WWW::IRail::API::Vehicle::make_request(\%opts);
104             my $http_res = $self->{client}->process($http_req, $callback);
105             my $response = WWW::IRail::API::Vehicle::parse_response( $http_res,
106             $opts{dataType} || $self->{dataType});
107             return $response;
108             }
109              
110             # function interface
111             sub irail {
112             my %args = ref $_[0] eq 'HASH' ? %{$_[0]} : @_;
113              
114             $args{dataType} ||= 'YAML';
115              
116             my $type = undef;
117              
118             $type = 'stations' if $args{station};
119             $type = 'connections' if $args{from} and $args{to};
120             $type = 'liveboard' if $args{from} xor $args{to};
121             $type = 'vehicle' if $args{vehicle};
122              
123             croak 'could not determine query type, did you specify the correct arguments?' unless $type;
124              
125             my $irail = new WWW::IRail::API;
126             my $fn = 'lookup_'.$type;
127              
128             return $irail->$fn(\%args);
129             }
130              
131              
132             42;
133              
134              
135             =pod
136              
137             =head1 VERSION
138              
139             version 0.003
140              
141             =head1 NAME
142              
143             WWW::IRail::API - A wrapper for the iRail.be API
144              
145             =head1 SYNOPSIS
146              
147             use WWW::IRail::API;
148             use Data::Dumper;
149              
150             ## OO interface ############################################################################
151              
152             my $irail = new WWW::IRail::API( dataType => 'YAML' );
153             my $trains_bxl_ost = $irail->lookup_connections(from => 'brussel noord', to => 'oostende');
154             print Dumper($trains_bxl_ost);
155              
156             ## functional interface ####################################################################
157            
158             # YAML liveboard with trains departing from *Brussel Noord*
159             print irail from => 'brussel noord'
160              
161             # YAML connections of trains between *Brussel Noord* and *Oostende* for tomorrow at 14:00
162             print irail from => 'brussel noord', to => 'oostende', date => 'tomorrow afternoon'
163              
164             # JSON station lookup of all stations matching qr/oost/
165             print irail station => qr/oost/, dataType => 'json'
166              
167             # XML vehicle lookup
168             print irail vehicle => 'BE.NMBS.CR2089', dataType => 'XML'
169              
170             # perl liveboard lookup
171             my $board = irail from => 'brussel noord', dataType => 'perl';
172              
173             =head1 DESCRIPTION
174              
175             WWW::IRail::API is a set of modules which allow you to query the
176             L API for Stations, Connections, Liveboard and Vehicle
177             data.
178              
179             =head1 METHODS
180              
181             =head2 new(I 'value'> | I<{key => 'value'}>)
182              
183             Constructor. Should normally be used without arguments, but if required you
184             could override some internals.
185              
186             my $irail = new WWW::IRail::API( client => 'LWP', dataType => 'JSON' );
187              
188             =head2 lookup_stations(I 'value'> | I<{key => 'value'}>)
189              
190             Method which takes a string or a hash(ref) and returns a list of stations in the set C.
191              
192             my @list = $irail->lookup_stations(filter => "brussel");
193             my @list = $irail->lookup_stations(filter => qr/brussel/i);
194             my @list = $irail->lookup_stations(filter => sub { /brussel/i } );
195              
196             my $json_string = $irail->lookup_stations(filter => qr/./, dataType => 'JSON');
197              
198             =head1 FEATURES
199              
200             =head2 Multiple output formats
201              
202             The returned results can be in either XML, JSON or YAML format. You can even
203             select between two flavours XML (xml, XML) to suit your taste. Ofcourse, if you
204             stay in perl, you can access the return object directly.
205              
206             =head2 Isolated parsers based on HTTP::[qw/Request Response/]
207              
208             The internal parsers consist of simply two subs. L which
209             takes in arbitrary query parameters and returns a L object. And
210             L which takes a L and builds an object which
211             it then returns in the desired output format.
212              
213             This makes them isolated pieces of code and ideal for testing or plugging into
214             other HTTP aware systems. You can thus safely B
215             in your code without ever using or loading any other of our modules.
216              
217             =head2 Support for sync or async pluggable clients
218              
219             Clients take L objects and B them by a request over
220             the wire. They then simply return the L or they will call a callback with
221             the response as a first parameter.
222              
223             If you are going to write your own client, you only need to implement a process
224             sub which will be called with ($http_request, $callback) parameters giving you
225             the option to either return from your process call and ignore the callback or
226             call the callback and go async from there.
227              
228             =head2 Natural data parsing
229              
230             If date matches C it will hand over parsing to L.
231             for example: date => 'friday at 6pm';
232              
233             =head1 METHODS
234              
235             =head1 LIMITATIONS
236              
237             =over 4
238              
239             =item *
240              
241             fetching the station list is an all or nothing operation, this should be cached
242              
243             =item *
244              
245             natural date parsing is in english only. It can also not parse 'friday afternoon' (yet)
246              
247             =back
248              
249             =head1 TODO
250              
251             =over 4
252              
253             =item *
254              
255             implement caching
256              
257             =item *
258              
259             implement AE/Coro LWP client (in another module)
260              
261             =back
262              
263             =head1 EXAMPLES
264              
265             Example you can run from the commandline to get you started quickly
266              
267             # install App::cpanminus the easy way
268             % curl -L http://cpanmin.us | sudo perl - --self-upgrade
269            
270             # install the WWW::IRail::API modules
271             % cpanm -S WWW::IRail::API
272              
273             # run a onliner from the commandline interface
274             % perl -MWWW::IRail::API -e 'print irail from => "brussel noord", to => "oostende", date => "next friday"
275              
276             =head1 SEE ALSO
277              
278             =over 4
279              
280             =item *
281              
282             L
283              
284             =item *
285              
286             L
287              
288             =item *
289              
290             L
291              
292             =item *
293              
294             L
295              
296             =back
297              
298             =head1 INSTALLATION
299              
300             See perlmodinstall for information and options on installing Perl modules.
301              
302             =head1 BUGS AND LIMITATIONS
303              
304             No bugs have been reported.
305              
306             Please report any bugs or feature requests through the web interface at
307             L.
308              
309             =head1 AUTHOR
310              
311             Tim Esselens
312              
313             =head1 COPYRIGHT AND LICENSE
314              
315             This software is copyright (c) 2010 by Tim Esselens.
316              
317             This is free software; you can redistribute it and/or modify it under
318             the same terms as the Perl 5 programming language system itself.
319              
320             =cut
321              
322              
323             __END__