Map-Tube-Brussels

 view release on metacpan or  search on metacpan

lib/Map/Tube/Brussels.pm  view on Meta::CPAN

# -*- perl -*-

#
# Author: Gisbert W. Selke, TapirSoft Selke & Selke GbR.
#
# Copyright (C) 2025 Gisbert W. Selke. All rights reserved.
# This package is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
# Mail: gws@cpan.org
#

package Map::Tube::Brussels;
use 5.14.0;
use version 0.77 ( );
use strict;
use warnings;

our $VERSION = version->declare('v0.2.1');

=encoding utf8

=head1 NAME

Map::Tube::Brussels - Interface to the Brussels tube map

=cut

use File::Share ':all';
use Moo;
use namespace::clean;

my %nametypes = map { $_ => 1 } qw(alt); # The permissible alternative nametypes. In our case, just 'alt'

has xml 	 => ( is  => 'ro', lazy => 1, default => sub { return dist_file('Map-Tube-Brussels', 'brussels-map.xml') } );
has nametype => ( is  => 'ro', default => '',
				  isa => sub { die __PACKAGE__ . ": ERROR: Invalid nametype for constructor: '$_[0]'" unless ( ( $_[0] eq '') || exists($nametypes{ $_[0] } ) ) },
                );

with 'Map::Tube';

before _validate_map_structure => sub {
  $_[1] = _relocate_alternatives( $_[1], '_' . $_[0]->{nametype} ) if ( exists( $_[0]->{nametype}) && ( $_[0]->{nametype} ne '' ) );
  $_[1] = _remove_alternatives( $_[1] );
};

sub _relocate_alternatives {
  my( $branch, $suffix ) = @_;
  for my $key( keys %{ $branch } ) {
    if ( ref( $branch->{$key} ) eq 'HASH' ) {
	  $branch->{$key} = _relocate_alternatives( $branch->{$key}, $suffix );
    } elsif ( ( ref( $branch->{$key} ) eq '' ) && ( $key eq ( 'name' . $suffix ) ) ) {
      $branch->{'name'} = $branch->{ 'name' . $suffix };
    } elsif ( ref( $branch->{$key} ) eq 'ARRAY' ) {
	  $branch->{$key} = [ map { _relocate_alternatives( $_, $suffix ) } @{ $branch->{$key} } ];
    }
  }
  return $branch;
}

sub _remove_alternatives {
  my($branch) = @_;
  for my $key( keys %{ $branch } ) {
    if ( ref( $branch->{$key} ) eq 'HASH' ) {
	  $branch->{$key} = _remove_alternatives( $branch->{$key} );
	} elsif ( ( ref( $branch->{$key} ) eq '' ) && ( $key eq 'name' ) ) {
	  for my $suffix ( keys(%nametypes) ) {
		delete $branch->{ $key . '_' . $suffix };
	  }
    } elsif ( ref( $branch->{$key} ) eq 'ARRAY' ) {
	  $branch->{$key} = [ map { _remove_alternatives($_) } @{ $branch->{$key} } ];
	}
  }
  return $branch;
}

=head1 SYNOPSIS

	use Map::Tube::Brussels;

	my $tube_nl  = Map::Tube::Brussels->new( nametype => 'alt' );
	my $route_nl = $tube_nl->get_shortest_route('Delacroix', 'Zuidstation')->preferred( );
	print "Route: $route_nl\n";

	my $tube_fr  = Map::Tube::Brussels->new( );
	my $route_fr = $tube_fr->get_shortest_route('Delacroix', 'Gare du Midi')->preferred( );
	print "Route: $route_fr\n";

=head1 DESCRIPTION

This module allows to find the shortest route between any two given tube
stations in Brussels. All interesting methods are provided by the role
L<Map::Tube>.

=head1 METHODS

=head2 CONSTRUCTOR

	use Map::Tube::Brussels;
	my $tube_fr = Map::Tube::Brussels->new( );
	my $tube_nl = Map::Tube::Brussels->new( nametype => 'alt' );

This will read the tube information from the shared file
F<brussels-map.xml>, which is part of the distribution.  Without
argument, French-language place names will be used.  With the value
C<'alt>' for C<nametype>, Dutch-language place names will be used.
Other values will throw an error.


=head2 nametype( )

This yields the nametype that was specified with the constructor call, or '' if none.


=head2 xml( )



( run in 1.607 second using v1.01-cache-2.11-cpan-71847e10f99 )