From f1ed161d81ee8277cf274b3c7b3a74fd717b30a1 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Fri, 20 Dec 2013 08:18:10 +0100 Subject: rename module to Travel::Status::DE::URA (it's pretty generic) --- Build.PL | 2 +- bin/aseag-m | 4 +- lib/Travel/Status/DE/ASEAG.pm | 350 ---------------------------------- lib/Travel/Status/DE/ASEAG/Result.pm | 157 ---------------- lib/Travel/Status/DE/URA.pm | 351 +++++++++++++++++++++++++++++++++++ lib/Travel/Status/DE/URA/Result.pm | 157 ++++++++++++++++ 6 files changed, 511 insertions(+), 510 deletions(-) delete mode 100644 lib/Travel/Status/DE/ASEAG.pm delete mode 100644 lib/Travel/Status/DE/ASEAG/Result.pm create mode 100644 lib/Travel/Status/DE/URA.pm create mode 100644 lib/Travel/Status/DE/URA/Result.pm diff --git a/Build.PL b/Build.PL index c8ecc23..ee0f662 100644 --- a/Build.PL +++ b/Build.PL @@ -14,7 +14,7 @@ Module::Build->new( configure_requires => { 'Module::Build' => 0.40, }, - module_name => 'Travel::Status::DE::ASEAG', + module_name => 'Travel::Status::DE::URA', license => 'perl', requires => { 'perl' => '5.10.1', diff --git a/bin/aseag-m b/bin/aseag-m index ca29fb6..bc4541a 100755 --- a/bin/aseag-m +++ b/bin/aseag-m @@ -13,7 +13,7 @@ use DateTime; use DateTime::Format::Duration; use Getopt::Long qw(:config no_ignore_case); use List::Util qw(max); -use Travel::Status::DE::ASEAG; +use Travel::Status::DE::URA; my (@grep_lines); my $full_route = 0; @@ -47,7 +47,7 @@ if ( @ARGV != 1 ) { my ($stop_name) = @ARGV; -my $status = Travel::Status::DE::ASEAG->new; +my $status = Travel::Status::DE::URA->new; sub show_help { my ($code) = @_; diff --git a/lib/Travel/Status/DE/ASEAG.pm b/lib/Travel/Status/DE/ASEAG.pm deleted file mode 100644 index 4be2cd2..0000000 --- a/lib/Travel/Status/DE/ASEAG.pm +++ /dev/null @@ -1,350 +0,0 @@ -package Travel::Status::DE::ASEAG; - -use strict; -use warnings; -use 5.010; - -no if $] >= 5.018, warnings => "experimental::smartmatch"; - -our $VERSION = '0.00'; - -use Carp qw(confess cluck); -use DateTime; -use Encode qw(encode decode); -use List::MoreUtils qw(none); -use LWP::UserAgent; -use Travel::Status::DE::ASEAG::Result; - -sub new { - my ( $class, %opt ) = @_; - - my $ua = LWP::UserAgent->new(%opt); - - my $self = { - full_routes => $opt{full_routes} // 0, - fuzzy => $opt{fuzzy} // 1, - hide_past => $opt{hide_past} // 1, - stop => $opt{stop}, - via => $opt{via}, - post => { - ReturnList => - 'lineid,linename,directionid,destinationtext,vehicleid,' - . 'tripid,estimatedtime,stopid,stoppointname' - }, - }; - - bless( $self, $class ); - - $ua->env_proxy; - - my $response = $ua->post( 'http://ivu.aseag.de/interfaces/ura/instant_V1', - $self->{post} ); - - if ( $response->is_error ) { - $self->{errstr} = $response->status_line; - return $self; - } - - $self->{raw_str} = $response->decoded_content; - - for my $dep ( split( /\r\n/, $self->{raw_str} ) ) { - $dep =~ s{^\[}{}; - $dep =~ s{\]$}{}; - - # first field == 4 => version information, no departure - if ( substr( $dep, 0, 1 ) != 4 ) { - push( @{ $self->{raw_list} }, [ split( /"?,"?/, $dep ) ] ); - } - } - - return $self; -} - -sub new_from_raw { - my ( $class, %opt ) = @_; - - my $self = { raw_str => $opt{raw_str}, }; - - for my $dep ( split( /\r\n/, $self->{raw} ) ) { - $dep =~ s{^\[}{}; - $dep =~ s{\]$}{}; - - # first field == 4 => version information, no departure - if ( substr( $dep, 0, 1 ) != 4 ) { - push( @{ $self->{raw_list} }, [ split( /"?,"?/, $dep ) ] ); - } - } - - return bless( $self, $class ); -} - -sub errstr { - my ($self) = @_; - - return $self->{errstr}; -} - -sub sprintf_date { - my ($e) = @_; - - return sprintf( '%02d.%02d.%d', - $e->getAttribute('day'), - $e->getAttribute('month'), - $e->getAttribute('year'), - ); -} - -sub sprintf_time { - my ($e) = @_; - - return sprintf( '%02d:%02d', - $e->getAttribute('hour'), - $e->getAttribute('minute'), - ); -} - -sub is_my_stop { - my ( $self, $stop, $my_stop, $fuzzy ) = @_; - - if ($fuzzy) { - return ( $stop =~ m{ $my_stop }ix ? 1 : 0 ); - } - else { - return ( $stop eq $my_stop ); - } -} - -sub results { - my ( $self, %opt ) = @_; - my @results; - - my $full_routes = $opt{full_routes} // $self->{full_routes} // 0; - my $fuzzy = $opt{fuzzy} // $self->{fuzzy} // 1; - my $hide_past = $opt{hide_past} // $self->{hide_past} // 1; - my $stop = $opt{stop} // $self->{stop}; - my $via = $opt{via} // $self->{via}; - - my $dt_now = DateTime->now( time_zone => 'Europe/Berlin' ); - my $ts_now = $dt_now->epoch; - - if ($via) { - $full_routes ||= 'after'; - } - - for my $dep ( @{ $self->{raw_list} } ) { - - my ( - $u1, $stopname, $stopid, $lineid, $linename, - $u2, $dest, $vehicleid, $tripid, $timestamp - ) = @{$dep}; - my @route; - - if ( $stop and not $self->is_my_stop( $stopname, $stop, $fuzzy ) ) { - next; - } - - if ( not $timestamp ) { - cluck("departure element without timestamp: $dep"); - next; - } - - my $dt_dep = DateTime->from_epoch( - epoch => $timestamp / 1000, - time_zone => 'Europe/Berlin' - ); - my $ts_dep = $dt_dep->epoch; - - if ( $hide_past and $dt_dep->subtract_datetime($dt_now)->is_negative ) { - next; - } - - if ($full_routes) { - @route = map { [ $_->[9] / 1000, $_->[1] ] } - grep { $_->[8] == $tripid } @{ $self->{raw_list} }; - - if ( $full_routes eq 'before' ) { - @route = grep { $_->[0] < $ts_dep } @route; - } - elsif ( $full_routes eq 'after' ) { - @route = grep { $_->[0] > $ts_dep } @route; - } - - if ( $via - and none { $self->is_my_stop( $_->[1], $via, $fuzzy ) } @route ) - { - next; - } - - if ($hide_past) { - @route = grep { $_->[0] >= $ts_now } @route; - } - - @route = map { $_->[0] } - sort { $a->[1] <=> $b->[1] } - map { [ $_, $_->[0] ] } @route; - - @route = map { - [ - DateTime->from_epoch( - epoch => $_->[0], - time_zone => 'Europe/Berlin' - ), - decode( 'UTF-8', $_->[1] ) - ] - } @route; - } - - push( - @results, - Travel::Status::DE::ASEAG::Result->new( - date => $dt_dep->strftime('%d.%m.%Y'), - time => $dt_dep->strftime('%H:%M:%S'), - datetime => $dt_dep, - line => $linename, - line_id => $lineid, - destination => decode( 'UTF-8', $dest ), - countdown => - $dt_dep->subtract_datetime($dt_now)->in_units('minutes'), - countdown_sec => - $dt_dep->subtract_datetime($dt_now)->in_units('seconds'), - route_timetable => [@route], - stop => $stopname, - stop_id => $stopid, - ) - ); - } - - @results = map { $_->[0] } - sort { $a->[1] <=> $b->[1] } - map { [ $_, $_->countdown ] } @results; - - $self->{results} = \@results; - - return @results; -} - -1; - -__END__ - -=head1 NAME - -Travel::Status::DE::ASEAG - unofficial ASEAG departure monitor - -=head1 SYNOPSIS - - use Travel::Status::DE::ASEAG; - - my $status = Travel::Status::DE::ASEAG->new( - stop => 'Aachen Bushof' - ); - - for my $d ($status->results) { - printf( - "%s %-5s %25s (in %d min)\n", - $d->time, $d->line, $d->destination, $d->countdown - ); - } - -=head1 VERSION - -version 1.04 - -=head1 DESCRIPTION - -Travel::Status::DE::ASEAG is an unofficial interface to an ASEAG departure -monitor. It reports all upcoming departures at a given place in real-time. -Schedule information is not included. - -=head1 METHODS - -=over - -=item my $status = Travel::Status::DE::ASEAG->new(I<%opt>) - -Requests the departures as specified by I and returns a new -Travel::Status::DE::ASEAG object. - -Accepts the same options is C<< $status->results >>. Options specified here -can be overridden later, but may limit the set of available departures. - - -=item $status->errstr - -In case of an HTTP request error, returns a string describing it. If none -occured, returns undef. - -=item $status->results(I<%opt>) - -Returns a list of Travel::Status::DE::ASEAG::Result(3pm) objects, each describing -one departure. - -Accepted parameters (all are optional): - -=over - -=item B => B|B|I (default 0) - -When set to a true value: Compute B fields in all -Travel::Status::DE::ASEAG::Result(3pm) objects, otherwise they will not be -set. - -B / B limits the timetable to stops before / after the stop -I (if set). - -=item B => I (default 1) - -A true value allows fuzzy matching for the I set above, a false one -requires an exact string match. - -=item B => I (default 1) - -Do not include past departures in the result list and the computed timetables. - -=item B => I - -Only return departures at stop I. - -=item B => I - -Only return departures containing I in their route. If B is set, -I must be in the route after the stop I. If, in addition to -that, B is set to B, I must be in the route -before the stop I. Respects B. Implies C<< full_routes> => 'after' >> unless -B is explicitly set to B / B / 1. - -=back - -=back - -=head1 DIAGNOSTICS - -None. - -=head1 DEPENDENCIES - -=over - -=item * Class::Accessor(3pm) - -=item * DateTime(3pm) - -=item * LWP::UserAgent(3pm) - -=back - -=head1 BUGS AND LIMITATIONS - -Many. - -=head1 SEE ALSO - -aseag-m(1), Travel::Status::DE::ASEAG::Result(3pm). - -=head1 AUTHOR - -Copyright (C) 2013 by Daniel Friesel Ederf@finalrewind.orgE - -=head1 LICENSE - -This module is licensed under the same terms as Perl itself. diff --git a/lib/Travel/Status/DE/ASEAG/Result.pm b/lib/Travel/Status/DE/ASEAG/Result.pm deleted file mode 100644 index 3d88261..0000000 --- a/lib/Travel/Status/DE/ASEAG/Result.pm +++ /dev/null @@ -1,157 +0,0 @@ -package Travel::Status::DE::ASEAG::Result; - -use strict; -use warnings; -use 5.010; - -use parent 'Class::Accessor'; - -our $VERSION = '0.00'; - -Travel::Status::DE::ASEAG::Result->mk_ro_accessors( - qw(countdown countdown_sec date datetime destination line line_id - route_timetable stop stop_id time) -); - -sub new { - my ( $obj, %conf ) = @_; - - my $ref = \%conf; - - return bless( $ref, $obj ); -} - -sub TO_JSON { - my ($self) = @_; - - return { %{$self} }; -} - -1; - -__END__ - -=head1 NAME - -Travel::Status::DE::ASEAG::Result - Information about a single -departure received by Travel::Status::DE::ASEAG - -=head1 SYNOPSIS - - for my $departure ($status->results) { - printf( - "At %s: %s to %s (in %d minutes)", - $departure->time, $departure->line, $departure->destination, - $departure->countdown - ); - } - -=head1 VERSION - -version 0.00 - -=head1 DESCRIPTION - -Travel::Status::DE::ASEAG::Result describes a single departure as obtained by -Travel::Status::DE::ASEAG. It contains information about the time, -line number and destination. - -=head1 METHODS - -=head2 ACCESSORS - -=over - -=item $departure->countdown - -Time in minutes from the time Travel::Status::DE::ASEAG was instantiated until -the bus will depart. - -=item $departure->countdown_sec - -Time in seconds from the time Travel::Status::DE::ASEAG was instantiated until -the bus will depart. - -=item $departure->date - -Departure date (DD.MM.YYYY) - -=item $departure->datetime - -DateTime object holding the departure date and time. - -=item $departure->destination - -Destination name. - -=item $departure->line - -The name of the line. - -=item $departure->line_id - -The number of the line. - -=item $departure->route_timetable - -Returns an arrayref of arrayrefs describing the entire route. I.e. -C<< [[$time1, $stop1], [$time2, $stop2], ...] >>. -The times are DateTime::Duration(3pm) objects, the stops are only names, -not IDs (subject to change). - -=item $departure->stop - -The stop belonging to this departure. - -=item $departure->stop_id - -The stop ID belonging to this departure. - -=item $departure->time - -Departure time (HH:MM:SS). - -=back - -=head2 INTERNAL - -=over - -=item $departure = Travel::Status::DE::ASEAG::Result->new(I<%data>) - -Returns a new Travel::Status::DE::ASEAG::Result object. You should not need to -call this. - -=item $departure->TO_JSON - -Allows the object data to be serialized to JSON. - -=back - -=head1 DIAGNOSTICS - -None. - -=head1 DEPENDENCIES - -=over - -=item Class::Accessor(3pm) - -=back - -=head1 BUGS AND LIMITATIONS - -Unknown. - -=head1 SEE ALSO - -Travel::Status::DE::ASEAG(3pm). - -=head1 AUTHOR - -Copyright (C) 2013 by Daniel Friesel Ederf@finalrewind.orgE - -=head1 LICENSE - -This module is licensed under the same terms as Perl itself. diff --git a/lib/Travel/Status/DE/URA.pm b/lib/Travel/Status/DE/URA.pm new file mode 100644 index 0000000..c016089 --- /dev/null +++ b/lib/Travel/Status/DE/URA.pm @@ -0,0 +1,351 @@ +package Travel::Status::DE::URA; + +use strict; +use warnings; +use 5.010; + +no if $] >= 5.018, warnings => "experimental::smartmatch"; + +our $VERSION = '0.00'; + +use Carp qw(confess cluck); +use DateTime; +use Encode qw(encode decode); +use List::MoreUtils qw(none); +use LWP::UserAgent; +use Travel::Status::DE::URA::Result; + +sub new { + my ( $class, %opt ) = @_; + + my $ua = LWP::UserAgent->new(%opt); + + my $self = { + full_routes => $opt{full_routes} // 0, + fuzzy => $opt{fuzzy} // 1, + hide_past => $opt{hide_past} // 1, + stop => $opt{stop}, + via => $opt{via}, + post => { + ReturnList => + 'lineid,linename,directionid,destinationtext,vehicleid,' + . 'tripid,estimatedtime,stopid,stoppointname' + }, + }; + + bless( $self, $class ); + + $ua->env_proxy; + + my $response = $ua->post( 'http://ivu.aseag.de/interfaces/ura/instant_V1', + $self->{post} ); + + if ( $response->is_error ) { + $self->{errstr} = $response->status_line; + return $self; + } + + $self->{raw_str} = $response->decoded_content; + + for my $dep ( split( /\r\n/, $self->{raw_str} ) ) { + $dep =~ s{^\[}{}; + $dep =~ s{\]$}{}; + + # first field == 4 => version information, no departure + if ( substr( $dep, 0, 1 ) != 4 ) { + push( @{ $self->{raw_list} }, [ split( /"?,"?/, $dep ) ] ); + } + } + + return $self; +} + +sub new_from_raw { + my ( $class, %opt ) = @_; + + my $self = { raw_str => $opt{raw_str}, }; + + for my $dep ( split( /\r\n/, $self->{raw} ) ) { + $dep =~ s{^\[}{}; + $dep =~ s{\]$}{}; + + # first field == 4 => version information, no departure + if ( substr( $dep, 0, 1 ) != 4 ) { + push( @{ $self->{raw_list} }, [ split( /"?,"?/, $dep ) ] ); + } + } + + return bless( $self, $class ); +} + +sub errstr { + my ($self) = @_; + + return $self->{errstr}; +} + +sub sprintf_date { + my ($e) = @_; + + return sprintf( '%02d.%02d.%d', + $e->getAttribute('day'), + $e->getAttribute('month'), + $e->getAttribute('year'), + ); +} + +sub sprintf_time { + my ($e) = @_; + + return sprintf( '%02d:%02d', + $e->getAttribute('hour'), + $e->getAttribute('minute'), + ); +} + +sub is_my_stop { + my ( $self, $stop, $my_stop, $fuzzy ) = @_; + + if ($fuzzy) { + return ( $stop =~ m{ $my_stop }ix ? 1 : 0 ); + } + else { + return ( $stop eq $my_stop ); + } +} + +sub results { + my ( $self, %opt ) = @_; + my @results; + + my $full_routes = $opt{full_routes} // $self->{full_routes} // 0; + my $fuzzy = $opt{fuzzy} // $self->{fuzzy} // 1; + my $hide_past = $opt{hide_past} // $self->{hide_past} // 1; + my $stop = $opt{stop} // $self->{stop}; + my $via = $opt{via} // $self->{via}; + + my $dt_now = DateTime->now( time_zone => 'Europe/Berlin' ); + my $ts_now = $dt_now->epoch; + + if ($via) { + $full_routes ||= 'after'; + } + + for my $dep ( @{ $self->{raw_list} } ) { + + my ( + $u1, $stopname, $stopid, $lineid, $linename, + $u2, $dest, $vehicleid, $tripid, $timestamp + ) = @{$dep}; + my @route; + + if ( $stop and not $self->is_my_stop( $stopname, $stop, $fuzzy ) ) { + next; + } + + if ( not $timestamp ) { + cluck("departure element without timestamp: $dep"); + next; + } + + my $dt_dep = DateTime->from_epoch( + epoch => $timestamp / 1000, + time_zone => 'Europe/Berlin' + ); + my $ts_dep = $dt_dep->epoch; + + if ( $hide_past and $dt_dep->subtract_datetime($dt_now)->is_negative ) { + next; + } + + if ($full_routes) { + @route = map { [ $_->[9] / 1000, $_->[1] ] } + grep { $_->[8] == $tripid } @{ $self->{raw_list} }; + + if ( $full_routes eq 'before' ) { + @route = grep { $_->[0] < $ts_dep } @route; + } + elsif ( $full_routes eq 'after' ) { + @route = grep { $_->[0] > $ts_dep } @route; + } + + if ( $via + and none { $self->is_my_stop( $_->[1], $via, $fuzzy ) } @route ) + { + next; + } + + if ($hide_past) { + @route = grep { $_->[0] >= $ts_now } @route; + } + + @route = map { $_->[0] } + sort { $a->[1] <=> $b->[1] } + map { [ $_, $_->[0] ] } @route; + + @route = map { + [ + DateTime->from_epoch( + epoch => $_->[0], + time_zone => 'Europe/Berlin' + ), + decode( 'UTF-8', $_->[1] ) + ] + } @route; + } + + push( + @results, + Travel::Status::DE::URA::Result->new( + date => $dt_dep->strftime('%d.%m.%Y'), + time => $dt_dep->strftime('%H:%M:%S'), + datetime => $dt_dep, + line => $linename, + line_id => $lineid, + destination => decode( 'UTF-8', $dest ), + countdown => + $dt_dep->subtract_datetime($dt_now)->in_units('minutes'), + countdown_sec => + $dt_dep->subtract_datetime($dt_now)->in_units('seconds'), + route_timetable => [@route], + stop => $stopname, + stop_id => $stopid, + ) + ); + } + + @results = map { $_->[0] } + sort { $a->[1] <=> $b->[1] } + map { [ $_, $_->countdown ] } @results; + + $self->{results} = \@results; + + return @results; +} + +1; + +__END__ + +=head1 NAME + +Travel::Status::DE::URA - unofficial departure monitor for URA-based +realtime data providers (e.g. ASEAG) + +=head1 SYNOPSIS + + use Travel::Status::DE::URA; + + my $status = Travel::Status::DE::URA->new( + stop => 'Aachen Bushof' + ); + + for my $d ($status->results) { + printf( + "%s %-5s %25s (in %d min)\n", + $d->time, $d->line, $d->destination, $d->countdown + ); + } + +=head1 VERSION + +version 1.04 + +=head1 DESCRIPTION + +Travel::Status::DE::URA is an unofficial interface URA-based realtime departure +monitors (as used e.g. by the ASEAG). It reports all upcoming departures at a +given place in real-time. Schedule information is not included. + +=head1 METHODS + +=over + +=item my $status = Travel::Status::DE::URA->new(I<%opt>) + +Requests the departures as specified by I and returns a new +Travel::Status::DE::USA object. + +Accepts the same options is C<< $status->results >>. Options specified here +can be overridden later, but may limit the set of available departures. + + +=item $status->errstr + +In case of an HTTP request error, returns a string describing it. If none +occured, returns undef. + +=item $status->results(I<%opt>) + +Returns a list of Travel::Status::DE::URA::Result(3pm) objects, each describing +one departure. + +Accepted parameters (all are optional): + +=over + +=item B => B|B|I (default 0) + +When set to a true value: Compute B fields in all +Travel::Status::DE::URA::Result(3pm) objects, otherwise they will not be +set. + +B / B limits the timetable to stops before / after the stop +I (if set). + +=item B => I (default 1) + +A true value allows fuzzy matching for the I set above, a false one +requires an exact string match. + +=item B => I (default 1) + +Do not include past departures in the result list and the computed timetables. + +=item B => I + +Only return departures at stop I. + +=item B => I + +Only return departures containing I in their route. If B is set, +I must be in the route after the stop I. If, in addition to +that, B is set to B, I must be in the route +before the stop I. Respects B. Implies C<< full_routes> => 'after' >> unless +B is explicitly set to B / B / 1. + +=back + +=back + +=head1 DIAGNOSTICS + +None. + +=head1 DEPENDENCIES + +=over + +=item * Class::Accessor(3pm) + +=item * DateTime(3pm) + +=item * LWP::UserAgent(3pm) + +=back + +=head1 BUGS AND LIMITATIONS + +Many. + +=head1 SEE ALSO + +aseag-m(1), Travel::Status::DE::URA::Result(3pm). + +=head1 AUTHOR + +Copyright (C) 2013 by Daniel Friesel Ederf@finalrewind.orgE + +=head1 LICENSE + +This module is licensed under the same terms as Perl itself. diff --git a/lib/Travel/Status/DE/URA/Result.pm b/lib/Travel/Status/DE/URA/Result.pm new file mode 100644 index 0000000..dbf619f --- /dev/null +++ b/lib/Travel/Status/DE/URA/Result.pm @@ -0,0 +1,157 @@ +package Travel::Status::DE::URA::Result; + +use strict; +use warnings; +use 5.010; + +use parent 'Class::Accessor'; + +our $VERSION = '0.00'; + +Travel::Status::DE::URA::Result->mk_ro_accessors( + qw(countdown countdown_sec date datetime destination line line_id + route_timetable stop stop_id time) +); + +sub new { + my ( $obj, %conf ) = @_; + + my $ref = \%conf; + + return bless( $ref, $obj ); +} + +sub TO_JSON { + my ($self) = @_; + + return { %{$self} }; +} + +1; + +__END__ + +=head1 NAME + +Travel::Status::DE::URA::Result - Information about a single +departure received by Travel::Status::DE::URA + +=head1 SYNOPSIS + + for my $departure ($status->results) { + printf( + "At %s: %s to %s (in %d minutes)", + $departure->time, $departure->line, $departure->destination, + $departure->countdown + ); + } + +=head1 VERSION + +version 0.00 + +=head1 DESCRIPTION + +Travel::Status::DE::URA::Result describes a single departure as obtained by +Travel::Status::DE::URA. It contains information about the time, +line number and destination. + +=head1 METHODS + +=head2 ACCESSORS + +=over + +=item $departure->countdown + +Time in minutes from the time Travel::Status::DE::URA was instantiated until +the bus will depart. + +=item $departure->countdown_sec + +Time in seconds from the time Travel::Status::DE::URA was instantiated until +the bus will depart. + +=item $departure->date + +Departure date (DD.MM.YYYY) + +=item $departure->datetime + +DateTime object holding the departure date and time. + +=item $departure->destination + +Destination name. + +=item $departure->line + +The name of the line. + +=item $departure->line_id + +The number of the line. + +=item $departure->route_timetable + +Returns an arrayref of arrayrefs describing the entire route. I.e. +C<< [[$time1, $stop1], [$time2, $stop2], ...] >>. +The times are DateTime::Duration(3pm) objects, the stops are only names, +not IDs (subject to change). + +=item $departure->stop + +The stop belonging to this departure. + +=item $departure->stop_id + +The stop ID belonging to this departure. + +=item $departure->time + +Departure time (HH:MM:SS). + +=back + +=head2 INTERNAL + +=over + +=item $departure = Travel::Status::DE::URA::Result->new(I<%data>) + +Returns a new Travel::Status::DE::URA::Result object. You should not need to +call this. + +=item $departure->TO_JSON + +Allows the object data to be serialized to JSON. + +=back + +=head1 DIAGNOSTICS + +None. + +=head1 DEPENDENCIES + +=over + +=item Class::Accessor(3pm) + +=back + +=head1 BUGS AND LIMITATIONS + +Unknown. + +=head1 SEE ALSO + +Travel::Status::DE::URA(3pm). + +=head1 AUTHOR + +Copyright (C) 2013 by Daniel Friesel Ederf@finalrewind.orgE + +=head1 LICENSE + +This module is licensed under the same terms as Perl itself. -- cgit v1.2.3