Skip to content

Commit

Permalink
Added new POD, tests and ability to pass arrayref to import which has…
Browse files Browse the repository at this point in the history
… names of PDL::Util functions to be made methods
  • Loading branch information
jberger committed Sep 21, 2011
1 parent 87fbfb7 commit b09ea0e
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 32 deletions.
31 changes: 31 additions & 0 deletions README.pod
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,34 @@ PDL::Util

Convenient utility functions/methods for use with PDL.

=head1 IMPORT

PDL::Util does not export anything by default. The exportable symbols come in two types, functions and methods. Methods is a strange word. When importing symbols one does not import methods. In this context a 'method' is a function which expects a piddle as its first argument.

A list of symbols may be imported as usual. Tags may be imported as ':functions' and ':methods'. More interestingly if an array reference or hash reference is passed as the last item in the import list, its contents will be passed to the L<add_pdl_method> function below, in which case these functions are imported into the PDL namespace and may be used as method calls. Note, when doing this for symbols from the PDL::Util module, only those listed in the ':methods' tag may be added as a method (this is the origin of the confusing terminology). Read carefully before using this functionality.

=head1 TAG :functions

=head2 add_pdl_method

=head1 TAG :methods

Again, the FUNCTIONS provided in the method tag are not automatically methods. They simply are function which are called with a PDL object (piddle) as their first argument. This function ARE available to be imported into the PDL namespace using the L<add_pdl_method> function describe above.

=head2 unroll

=head2 export2d

export2d($pdl, $fh, ',');
-- or --
$pdl->export2d($fh, ',');

C<export2d> may take up to 2 optional arguments, a lexical filehandle (or globref, e.g. C<\*FILE>) to write to, and a string containing a column separator. The defaults, if arguments are not given are to print to STDOUT and use a single space as the column separator. The order does not matter, the method will determine whether an argument refers to a file or not. This is done so that one may call either

$pdl->export2d($fh);
$pdl->export2d(',');

and it will do what you mean. Unfortunately this means that unlike C<wcols> one cannot use a filename rather than a filehandle; C<export2d> would interpret the string as the column separator!

The method returns the number of columns that were written.

105 changes: 74 additions & 31 deletions lib/PDL/Util.pm
Original file line number Diff line number Diff line change
@@ -1,36 +1,75 @@
package PDL::Util;

=head1 NAME
PDL::Util
=head1 SYNOPSIS
use PDL;
use PDL::Util 'export2d';
my $pdl = rvals(6,4);
open my $fh, '>', 'file.dat';
export2d($pdl, $fh);
=head1 DESCRIPTION
Convenient utility functions/methods for use with PDL.
=cut

use PDL;
use Scalar::Util qw/openhandle blessed/;

use Carp;

use parent 'Exporter';
our @EXPORT_OK = qw/
add_pdl_method
export2d
unroll
/;
our %EXPORT_TAGS = (
all => \@EXPORT_OK,
functions => [qw/add_pdl_method/],
methods => [qw/unroll export2d/],
);

our @EXPORT_OK;
push @EXPORT_OK, @$_ for values %EXPORT_TAGS;

$EXPORT_TAGS{'all'} = \@EXPORT_OK;

=head1 IMPORT
PDL::Util does not export anything by default. The exportable symbols come in two types, functions and methods. Methods is a strange word. When importing symbols one does not import methods. In this context a 'method' is a function which expects a piddle as its first argument.
A list of symbols may be imported as usual. Tags may be imported as ':functions' and ':methods'. More interestingly if an array reference or hash reference is passed as the last item in the import list, its contents will be passed to the L<add_pdl_method> function below, in which case these functions are imported into the PDL namespace and may be used as method calls. Note, when doing this for symbols from the PDL::Util module, only those listed in the ':methods' tag may be added as a method (this is the origin of the confusing terminology). Read carefully before using this functionality.
=cut

sub import {
my $package = shift;
return 1 unless @_;

my $ref_last = ref $_[-1] || '';
my $method_spec = $ref_last eq 'HASH' ? pop : 0;
my $method_spec = ( grep {$ref_last eq $_} qw/HASH ARRAY/ ) ? pop : 0;

add_pdl_method($method_spec) if ($method_spec);

__PACKAGE__->export_to_level(1, $package, @_) if @_;
}

=head1 TAG :functions
=head2 add_pdl_method
=cut

sub add_pdl_method {
my $spec = shift;
croak 'make_pdl_method expects a hash reference as its argument'
unless ref $spec eq 'HASH';
croak 'make_pdl_method expects a hash or array reference as its argument'
unless grep {ref $spec eq $_} qw/HASH ARRAY/;

if (ref $spec eq 'ARRAY') {
$spec = { map { $_ => $_ } @$spec };
}

foreach my $method (keys %$spec) {
my $function = $spec->{$method};
Expand All @@ -41,7 +80,7 @@ PDL already provides a method named '$method', read the PDL::Util documentation
MESSAGE

unless (ref $function && ref $function eq 'CODE') {
if ( 1 == grep { $_ eq $function } @EXPORT_OK ) {
if ( 1 == grep { $_ eq $function } @{ $EXPORT_TAGS{'methods'} } ) {
no strict 'refs';
$function = \&{ 'PDL::Util::' . $function };
} else {
Expand All @@ -54,6 +93,14 @@ MESSAGE
}
}

=head1 TAG :methods
Again, the FUNCTIONS provided in the method tag are not automatically methods. They simply are function which are called with a PDL object (piddle) as their first argument. This function ARE available to be imported into the PDL namespace using the L<add_pdl_method> function describe above.
=head2 unroll
=cut

sub unroll {
my $pdl = shift;

Expand All @@ -69,6 +116,23 @@ sub unroll {

}

=head2 export2d
export2d($pdl, $fh, ',');
-- or --
$pdl->export2d($fh, ',');
C<export2d> may take up to 2 optional arguments, a lexical filehandle (or globref, e.g. C<\*FILE>) to write to, and a string containing a column separator. The defaults, if arguments are not given are to print to STDOUT and use a single space as the column separator. The order does not matter, the method will determine whether an argument refers to a file or not. This is done so that one may call either
$pdl->export2d($fh);
$pdl->export2d(',');
and it will do what you mean. Unfortunately this means that unlike C<wcols> one cannot use a filename rather than a filehandle; C<export2d> would interpret the string as the column separator!
The method returns the number of columns that were written.
=cut

sub export2d {
my ($pdl, $fh, $sep);
$pdl = shift;
Expand Down Expand Up @@ -107,25 +171,4 @@ sub export2d {

1;

__END__
__POD__
=head1 NAME
PDL::Util
=head1 SYNOPSIS
use PDL;
use PDL::Util 'export2d';
my $pdl = rvals(6,4);

open my $fh, '>', 'file.dat';
export2d($pdl, $fh);
=head1 DESCRIPTION
Convenient utility functions/methods for use with PDL.
=cut
6 changes: 5 additions & 1 deletion t/10-method.t → t/10-add_method.t
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use strict;
use warnings;

use Test::More tests => 3;
use Test::More tests => 5;
use PDL;
use_ok('PDL::Util', 'add_pdl_method');

Expand All @@ -13,6 +13,10 @@ ok($pdl->can('mymethod_ref'), "method added by code reference");
add_pdl_method({ 'mymethod_unroll' => 'unroll' });
ok($pdl->can('mymethod_unroll'), "method added by name from PDL::Util's exportable function");

add_pdl_method(['unroll', 'export2d']);
ok($pdl->can('unroll'), "'unroll' method added by array from PDL::Util's exportable function");
ok($pdl->can('export2d'), "'export2d' method added by array from PDL::Util's exportable function");

sub method1 {
my $pdl = shift;
return 1;
Expand Down
File renamed without changes.
12 changes: 12 additions & 0 deletions t/25-import_method_array.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use strict;
use warnings;

use PDL;
use Test::More tests => 3;

use_ok('PDL::Util', ['unroll', 'export2d']);

my $pdl = zeros(5,5);
ok($pdl->can('unroll'), "'unroll' method imported during 'use'");
ok($pdl->can('export2d'), "'export2d' method imported during 'use'");

0 comments on commit b09ea0e

Please sign in to comment.