Wiki-Toolkit-Plugin-Locator-Grid-0.05/0002755000175000017500000000000010441357271017072 5ustar domdom00000000000000Wiki-Toolkit-Plugin-Locator-Grid-0.05/t/0002755000175000017500000000000010441357271017335 5ustar domdom00000000000000Wiki-Toolkit-Plugin-Locator-Grid-0.05/t/01_load.t0000644000175000017500000000013210431601043020717 0ustar domdom00000000000000use strict; use Test::More tests => 1; use_ok( "Wiki::Toolkit::Plugin::Locator::Grid" ); Wiki-Toolkit-Plugin-Locator-Grid-0.05/t/03_different_names.t0000644000175000017500000000231210431601043023135 0ustar domdom00000000000000use strict; use Wiki::Toolkit::Plugin::Locator::Grid; use Wiki::Toolkit::TestLib; use Test::More; my $iterator = Wiki::Toolkit::TestLib->new_wiki_maker; unless ( $iterator->number ) { plan skip_all => "No backends configured"; exit 0; } plan tests => ( $iterator->number * 3 ); while ( my $wiki = $iterator->new_wiki ) { my $locator = Wiki::Toolkit::Plugin::Locator::Grid->new( x => "easting", y => "northing", ); isa_ok( $locator, "Wiki::Toolkit::Plugin::Locator::Grid" ); $wiki->register_plugin( plugin => $locator ); $wiki->write_node( "11", "grid point", undef, { easting => 1000, northing => 1000 } ) or die "Can't write node"; $wiki->write_node( "12", "grid point", undef, { easting => 1000, northing => 2000 } ) or die "Can't write node"; my ($x, $y) = $locator->coordinates( node => "11" ); is_deeply( [ $x, $y ], [ 1000, 1000 ], "->coordinates works with different names" ); my $distance = $locator->distance( from_node => "11", to_node => "12" ); is( $distance, 1000, "...so does ->distance" ); } Wiki-Toolkit-Plugin-Locator-Grid-0.05/t/02_locator.t0000644000175000017500000002012110431601043021444 0ustar domdom00000000000000use strict; use Wiki::Toolkit::Plugin::Locator::Grid; use Wiki::Toolkit::TestLib; use Test::More; my $iterator = Wiki::Toolkit::TestLib->new_wiki_maker; unless ( $iterator->number ) { plan skip_all => "No backends configured"; exit 0; } plan tests => ( $iterator->number * 21 ); while ( my $wiki = $iterator->new_wiki ) { print "# Store: " . (ref $wiki->store) . "\n"; my $locator = eval { Wiki::Toolkit::Plugin::Locator::Grid->new; }; is( $@, "", "'new' doesn't croak" ); isa_ok( $locator, "Wiki::Toolkit::Plugin::Locator::Grid" ); $wiki->register_plugin( plugin => $locator ); $wiki->write_node( "Jerusalem Tavern", "Pub in Clerkenwell with St Peter's beer.", undef, { x => 531674, y => 181950 } ) or die "Can't write node"; $wiki->write_node( "Calthorpe Arms", "Hmmm, beeer.", undef, { x => 530780, y => 182355 } ) or die "Can't write node"; $wiki->write_node( "Albion", "Pub in Islington", undef, { x => 531206, y => 183965 } ) or die "Can't write node"; $wiki->write_node( "Duke of Cambridge", "Pub in Islington", undef, { x => 531987, y => 183417 } ) or die "Can't write node"; $wiki->write_node( "Ken Livingstone", "Congestion charge hero" ) or die "Can't write node"; $wiki->write_node( "22", "grid point", undef, { x => 2000, y => 2000 } ) or die "Can't write node"; $wiki->write_node( "11", "grid point", undef, { x => 1000, y => 1000 } ) or die "Can't write node"; $wiki->write_node( "21", "grid point", undef, { x => 2000, y => 1000 } ) or die "Can't write node"; $wiki->write_node( "21 clone", "grid point clone", undef, { x => 2000, y => 1000 } ) or die "Can't write node"; # Co-ordinates. my ( $x, $y ) = $locator->coordinates( node => "Jerusalem Tavern" ); is_deeply( [ $x, $y ], [ 531674, 181950 ], "->coordinates works" ); # Distance between two places. my $distance = $locator->distance( from_node => "Jerusalem Tavern", to_node => "Calthorpe Arms" ); my $otherway = $locator->distance( to_node => "Jerusalem Tavern", from_node => "Calthorpe Arms" ); print "# Distance is $distance m\n"; print "# Or in the other direction is $otherway m\n"; is( $distance, $otherway, "->distance seems consistent" ); $distance = $locator->distance( from_node => "Calthorpe Arms", to_node => "Ken Livingstone" ); is( $distance, undef, "...and returns undef if one node has no co-ords"); $distance = $locator->distance( from_node => "Calthorpe Arms", to_node => "nonexistent node" ); is( $distance, undef, "...or if one node does not exist" ); # All things within a given distance. print "# " . $locator->distance( from_node => "Duke of Cambridge", to_node => "Albion" ) . "\n"; my @close = $locator->find_within_distance( node => "Albion", metres => 1000 ); is_deeply( [ sort @close ], [ "Duke of Cambridge" ], "find_within_distance works as expected on London data" ); @close = $locator->find_within_distance( node => "Albion", kilometres => 1 ); is_deeply( [ sort @close ], [ "Duke of Cambridge" ], "...with distances specified in km rather than metres too" ); my @unit = $locator->find_within_distance( node => "11", metres => 1000 ); print "# Found: " . join(", ", @unit) . "\n"; my %unit_hash = map { $_ => 1 } @unit; ok( defined $unit_hash{"21"}, "and on test grid finds things it should"); ok( ! defined $unit_hash{"22"}, "...and not corner points" ); ##### distance with start/end point as co-ords $distance = $locator->distance(from_x => 531467, from_y => 183246, to_node => "Duke of Cambridge" ); is( $distance, 547, "->distance works with start point as co-ords" ); $distance = $locator->distance(from_node => "Duke of Cambridge", to_x => 531206, to_y => 183965 ); is( $distance, 954, "...and with end point as co-ords" ); ##### find_within_distance with start point as co-ords my @things = $locator->find_within_distance( x => 530774, y => 182260, metres => 400 ); is_deeply( \@things, [ "Calthorpe Arms" ], "->find_within_distance works with start point as co-ords" ); ##### Check that we're accessing the *latest* data. my %node_data = $wiki->retrieve_node( "Calthorpe Arms" ); $wiki->write_node( "Calthorpe Arms", "Let's pretend it's in Islington.", $node_data{checksum}, { x => 531900, y => 183500 } ) or die "Can't write node"; # ...co-ordinates ($x, $y) = $locator->coordinates( node => "Calthorpe Arms" ); is_deeply( [ $x, $y ], [ 531900, 183500 ], "->coordinates picks up latest data, not old stuff" ); # ...distance $distance = $locator->distance( from_node => "Duke of Cambridge", to_node => "Calthorpe Arms" ); is( $distance, 120, "...as does ->distance" ); print "# Distance is $distance m\n"; print "# " . $locator->distance( from_node => "Jerusalem Tavern", to_node => "Calthorpe Arms" ) . "\n"; # ...within given distance @close = $locator->find_within_distance( node => "Jerusalem Tavern", metres => 1000 ); print "# Found near JT: " . join(", ", @close) . "\n"; my %close_hash = map { $_ => 1 } @close; ok( ! defined $close_hash{"Calthorpe Arms"}, "...as does ->find_within_distance, for things which used to be close enough but now aren't" ); @close = $locator->find_within_distance( node => "Duke of Cambridge", metres => 125 ); print "# Found near DoC: " . join(", ", @close) . "\n"; %close_hash = map { $_ => 1 } @close; ok( defined $close_hash{"Calthorpe Arms"}, "...and for things which didn't use to be close enough but now are"); # Check that we only get things once. @close = $locator->find_within_distance( node => "Duke of Cambridge", metres => 1250 ); print "# Found: " . join(", ", @close) . "\n"; my @dupes = grep { /Calthorpe Arms/ } @close; is( scalar @dupes, 1, "...and only picks things up once, even if multiple versions exist"); # Check we don't get deleted things. $wiki->delete_node("Calthorpe Arms"); @close = $locator->find_within_distance( node => "Duke of Cambridge", metres => 125 ); print "# Found near DoC: " . join(", ", @close) . "\n"; is( scalar @close, 0, "...and doesn't pick up deleted nodes" ); # Check things with no co-ordinates don't get treated as being at # the origin. my @stuff = $locator->find_within_distance( node => "Duke of Cambridge", metres => 600000 ); my %stuff_hash = map { $_ => 1 } @stuff; ok( ! defined $stuff_hash{"Ken Livingstone"}, "...or things with no co-ordinates" ); # Check that distinct things with identical co-ords are found. my @nodes = $locator->find_within_distance( node => "21", metres => 5, ); is_deeply( \@nodes, [ "21 clone" ], "find_within_distance finds nodes with identical co-ords" ); } Wiki-Toolkit-Plugin-Locator-Grid-0.05/MANIFEST0000644000175000017500000000022110431607672020216 0ustar domdom00000000000000Changes MANIFEST Makefile.PL README SIGNATURE lib/Wiki/Toolkit/Plugin/Locator/Grid.pm t/01_load.t t/02_locator.t t/03_different_names.t META.yml Wiki-Toolkit-Plugin-Locator-Grid-0.05/META.yml0000644000175000017500000000071310441357271020342 0ustar domdom00000000000000# http://module-build.sourceforge.net/META-spec.html #XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# name: Wiki-Toolkit-Plugin-Locator-Grid version: 0.05 version_from: lib/Wiki/Toolkit/Plugin/Locator/Grid.pm installdirs: site requires: Carp: 0 Test::More: 0 Wiki::Toolkit: 0 distribution_type: module generated_by: ExtUtils::MakeMaker version 6.17 Wiki-Toolkit-Plugin-Locator-Grid-0.05/Changes0000644000175000017500000000107710441357233020366 0ustar domdom000000000000000.05 6 Jun 2006 Internal speed improvement and bugfix for location SQL query 0.04 14 May 2006 Rename to Wiki::Toolkit::Plugin::Locator::Grid Move to new Wiki::Toolkit schema. 0.03 5 January 2005 Fix to tests so they don't die when no backends are configured (spotted by Bob Walker). 0.02 13 December 2004 Kludge to make the distance searching work with SQLite 3. 0.01 23 November 2004 Initial release. This module is a generalisation from version 0.09 of CGI::Wiki::Plugin::Locator::UK. Wiki-Toolkit-Plugin-Locator-Grid-0.05/lib/0002755000175000017500000000000010441357271017640 5ustar domdom00000000000000Wiki-Toolkit-Plugin-Locator-Grid-0.05/lib/Wiki/0002755000175000017500000000000010441357271020543 5ustar domdom00000000000000Wiki-Toolkit-Plugin-Locator-Grid-0.05/lib/Wiki/Toolkit/0002755000175000017500000000000010441357271022170 5ustar domdom00000000000000Wiki-Toolkit-Plugin-Locator-Grid-0.05/lib/Wiki/Toolkit/Plugin/0002755000175000017500000000000010441357271023426 5ustar domdom00000000000000Wiki-Toolkit-Plugin-Locator-Grid-0.05/lib/Wiki/Toolkit/Plugin/Locator/0002755000175000017500000000000010441357271025031 5ustar domdom00000000000000Wiki-Toolkit-Plugin-Locator-Grid-0.05/lib/Wiki/Toolkit/Plugin/Locator/Grid.pm0000644000175000017500000002203110441357221026243 0ustar domdom00000000000000package Wiki::Toolkit::Plugin::Locator::Grid; use strict; use vars qw( $VERSION @ISA ); $VERSION = '0.05'; use Carp qw( croak ); use Wiki::Toolkit::Plugin; @ISA = qw( Wiki::Toolkit::Plugin ); =head1 NAME Wiki::Toolkit::Plugin::Locator::Grid - A Wiki::Toolkit plugin to manage co-ordinate data. =head1 DESCRIPTION Access to and calculations using co-ordinate metadata supplied to a Wiki::Toolkit wiki when writing a node. B This is I access. If you want to write to a node's metadata, you need to do it using the C method of L. We assume that the points are located on a flat, square grid with unit squares of side 1 metre. =head1 SYNOPSIS use Wiki::Toolkit; use Wiki::Toolkit::Plugin::Locator::Grid; my $wiki = Wiki::Toolkit->new( ... ); my $locator = Wiki::Toolkit::Plugin::Locator::Grid->new; $wiki->register_plugin( plugin => $locator ); $wiki->write_node( "Jerusalem Tavern", "A good pub", $checksum, { x => 531674, y => 181950 } ) or die "argh"; # Just retrieve the co-ordinates. my ( $x, $y ) = $locator->coordinates( node => "Jerusalem Tavern" ); # Find the straight-line distance between two nodes, in metres. my $distance = $locator->distance( from_node => "Jerusalem Tavern", to_node => "Calthorpe Arms" ); # Find all the things within 200 metres of a given place. my @others = $locator->find_within_distance( node => "Albion", metres => 200 ); # Maybe our wiki calls the x and y co-ordinates something else. my $locator = Wiki::Toolkit::Plugin::Locator::Grid->new( x => "os_x", y => "os_y", ); =head1 METHODS =over 4 =item B # By default we assume that x and y co-ordinates are stored in # metadata called "x" and "y". my $locator = Wiki::Toolkit::Plugin::Locator::Grid->new; # But maybe our wiki calls the x and y co-ordinates something else. my $locator = Wiki::Toolkit::Plugin::Locator::Grid->new( x => "os_x", y => "os_y", ); =cut sub new { my $class = shift; my $self = {}; bless $self, $class; return $self->_init( @_ ); } sub _init { my ($self, %args) = @_; $self->{x} = $args{x} || "x"; $self->{y} = $args{y} || "y"; return $self; } =item B my $x_field = $locator->x_field; An accessor, returns the name of the metadata field used to store the x-coordinate. =cut sub x_field { my $self = shift; return $self->{x}; } =item B my $y_field = $locator->y_field; An accessor, returns the name of the metadata field used to store the y-coordinate. =cut sub y_field { my $self = shift; return $self->{y}; } =item B my ($x, $y) = $locator->coordinates( node => "Jerusalem Tavern" ); Returns the x and y co-ordinates stored as metadata last time the node was written. =cut sub coordinates { my ($self, %args) = @_; my $store = $self->datastore; # This is the slightly inefficient but neat and tidy way to do it - # calling on as much existing stuff as possible. my %node_data = $store->retrieve_node( $args{node} ); my %metadata = %{$node_data{metadata}}; return ($metadata{$self->{x}}[0], $metadata{$self->{y}}[0]); } =item B # Find the straight-line distance between two nodes, in metres. my $distance = $locator->distance( from_node => "Jerusalem Tavern", to_node => "Calthorpe Arms" ); # Or in kilometres, and between a node and a point. my $distance = $locator->distance( from_x => 531467, from_y => 183246, to_node => "Duke of Cambridge", unit => "kilometres" ); Defaults to metres if C is not supplied or is not recognised. Recognised units at the moment: C, C. Returns C if one of the endpoints does not exist, or does not have both co-ordinates defined. The C specification of an endpoint overrides the x/y co-ords if both specified (but don't do that). B Works to the nearest metre. Well, actually, calls C and rounds down, but if anyone cares about that they can send a patch. =cut sub distance { my ($self, %args) = @_; $args{unit} ||= "metres"; my (@from, @to); if ( $args{from_node} ) { @from = $self->coordinates( node => $args{from_node} ); } elsif ( $args{from_x} and $args{from_y} ) { @from = @args{ qw( from_x from_y ) }; } if ( $args{to_node} ) { @to = $self->coordinates( node => $args{to_node} ); } elsif ( $args{to_x} and $args{to_y} ) { @to = @args{ qw( to_x to_y ) }; } return undef unless ( $from[0] and $from[1] and $to[0] and $to[1] ); my $metres = int( sqrt( ($from[0] - $to[0])**2 + ($from[1] - $to[1])**2 ) + 0.5 ); if ( $args{unit} eq "metres" ) { return $metres; } else { return $metres/1000; } } =item B # Find all the things within 200 metres of a given place. my @others = $locator->find_within_distance( node => "Albion", metres => 200 ); # Or within 200 metres of a given location. my @things = $locator->find_within_distance( x => 530774, y => 182260, metres => 200 ); Units currently understood: C, C. If both C and C/C are supplied then C takes precedence. Croaks if insufficient start point data supplied. =cut sub find_within_distance { my ($self, %args) = @_; my $store = $self->datastore; my $dbh = eval { $store->dbh; } or croak "find_within_distance is only implemented for database stores"; my $metres = $args{metres} || ($args{kilometres} * 1000) || croak "Please supply a distance"; my ($sx, $sy); if ( $args{node} ) { ($sx, $sy) = $self->coordinates( node => $args{node} ); } elsif ( $args{x} and $args{y} ) { ($sx, $sy) = @args{ qw( x y ) }; } else { croak "Insufficient start location data supplied"; } # Only consider nodes within the square containing the circle of # radius $distance. The SELECT DISTINCT is needed because we might # have multiple versions in the table. my $sql = "SELECT DISTINCT x.name ". "FROM node AS x ". "INNER JOIN metadata AS mx ". " ON (mx.node_id = x.id AND mx.version = x.version) ". "INNER JOIN node AS y ". " ON (x.id = y.id) ". "INNER JOIN metadata my ". " ON (my.node_id = y.id AND my.version = y.version) ". " WHERE mx.metadata_type = '$self->{x}' ". " AND my.metadata_type = '$self->{y}' ". " AND mx.metadata_value >= " . ($sx - $metres) . " AND mx.metadata_value <= " . ($sx + $metres) . " AND my.metadata_value >= " . ($sy - $metres) . " AND my.metadata_value <= " . ($sy + $metres); $sql .= " AND x.name != " . $dbh->quote($args{node}) if $args{node}; # Postgres is a fussy bugger. if ( ref $store eq "Wiki::Toolkit::Store::Pg" ) { $sql =~ s/metadata_value/metadata_value::integer/gs; } # SQLite 3 is even fussier. if ( ref $store eq "Wiki::Toolkit::Store::SQLite" && $DBD::SQLite::VERSION >= "1.00" ) { $sql =~ s/metadata_value/metadata_value+0/gs; # yuck } my $sth = $dbh->prepare($sql); $sth->execute; my @results; while ( my ($result) = $sth->fetchrow_array ) { my $dist = $self->distance( from_x => $sx, from_y => $sy, to_node => $result, unit => "metres" ); if ( defined $dist && $dist <= $metres ) { push @results, $result; } } return @results; } =head1 SEE ALSO =over 4 =item * L =item * L - an application that uses this plugin. =back =head1 AUTHOR Kake Pugh (kake@earth.li). The Wiki::Toolkit team (http://www.wiki-toolkit.org/) =head1 COPYRIGHT Copyright (C) 2004 Kake L Pugh. All Rights Reserved. Copyright (C) 2006 the Wiki::Toolkit Team. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 CREDITS This module is based heavily on (and is the replacement for) L. The following thanks are due to people who helped with L: Nicholas Clark found a very silly bug in a pre-release version, oops :) Stephen White got me thinking in the right way to implement C. Marcel Gruenauer helped me make C work properly with postgres. =cut 1; Wiki-Toolkit-Plugin-Locator-Grid-0.05/SIGNATURE0000644000175000017500000000237010431607740020354 0ustar domdom00000000000000This file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.44. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 SHA1 40e7e2bdffb5441af9ff1e5014a224ba8189fe63 Changes SHA1 bbda2c921c2fa873513cb049b612d4a3b8c31653 MANIFEST SHA1 2ecf30f4806015aaecbc24876c99f7eb901c8bc0 META.yml SHA1 f8d9448fb639f13f2337ff5865a6a059ab157d1e Makefile.PL SHA1 974d4e934b14c5dcf71cd9f431d5d0f8cbc291d1 README SHA1 98dd581b7e8adeb583ede728f0952d8a01a177bd lib/Wiki/Toolkit/Plugin/Locator/Grid.pm SHA1 9dca3f1800af7a261155bda84322ac4292b688b7 t/01_load.t SHA1 9cdbd7692cd20671680094210a7ad3b81742656d t/02_locator.t SHA1 f2a4ce19298a4b9f7b010763eb2aa03249d59b76 t/03_different_names.t -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFEZw/gYzuFKFF44qURAruEAJ9K/pyjXBZH7W+u8Cb1wdEieZGj2QCgwKH3 dL6IoRu2FQcGetNY1IED4jY= =X6Xc -----END PGP SIGNATURE----- Wiki-Toolkit-Plugin-Locator-Grid-0.05/README0000644000175000017500000000075110431607160017745 0ustar domdom00000000000000NAME Wiki::Toolkit::Plugin::Locator::Grid - A Wiki::Toolkit plugin to manage co-ordinate data. DESCRIPTION Access to and calculations using co-ordinate metadata supplied to a Wiki::Toolkit wiki when writing a node. Note: This is *read-only* access. If you want to write to a node's metadata, you need to do it using the "write_node" method of Wiki::Toolkit. We assume that the points are located on a flat, square grid with unit squares of side 1 metre. Wiki-Toolkit-Plugin-Locator-Grid-0.05/Makefile.PL0000644000175000017500000000061210431601747021040 0ustar domdom00000000000000use ExtUtils::MakeMaker; WriteMakefile( NAME => "Wiki::Toolkit::Plugin::Locator::Grid", VERSION_FROM => "lib/Wiki/Toolkit/Plugin/Locator/Grid.pm", PREREQ_PM => { 'Wiki::Toolkit' => 0, 'Test::More' => 0, 'Carp' => 0 }, clean => { FILES => "t/sqlite-test.db t/sii-db-file-test.db/ t/plucene/" } );