[BACK]Return to Todo.pm CVS log [TXT][DIR] Up to [local] / todotxt / Text-Todo / lib / Text

Annotation of todotxt/Text-Todo/lib/Text/Todo.pm, Revision 1.6

1.1       andrew      1: package Text::Todo;
                      2:
1.6     ! andrew      3: # $RedRiver: Todo.pm,v 1.5 2010/01/09 05:00:21 andrew Exp $
1.1       andrew      4:
                      5: use warnings;
                      6: use strict;
                      7: use Carp;
                      8:
1.2       andrew      9: use Class::Std::Utils;
                     10: use Text::Todo::Entry;
1.5       andrew     11: use File::Spec;
                     12:
                     13: use Data::Dumper;
1.2       andrew     14:
1.1       andrew     15: use version; our $VERSION = qv('0.0.1');
                     16:
1.2       andrew     17: {
                     18:
1.5       andrew     19:     my %path_of;
1.2       andrew     20:     my %list_of;
1.1       andrew     21:
1.2       andrew     22:     sub new {
1.5       andrew     23:         my ( $class, $options ) = @_;
1.1       andrew     24:
1.2       andrew     25:         my $self = bless anon_scalar(), $class;
                     26:         my $ident = ident($self);
                     27:
1.5       andrew     28:         $path_of{$ident} = {
                     29:             todo_dir    => undef,
                     30:             todo_file   => 'todo.txt',
                     31:             done_file   => undef,
                     32:             report_file => undef,
                     33:         };
                     34:
                     35:         if ($options) {
                     36:             if ( ref $options eq 'HASH' ) {
                     37:                 foreach my $opt ( keys %{$options} ) {
                     38:                     if ( exists $path_of{$ident}{$opt} ) {
                     39:                         $self->_path_to( $opt, $options->{$opt} );
                     40:                     }
                     41:                     else {
                     42:                         carp "Invalid option [$opt]";
                     43:                     }
                     44:                 }
                     45:             }
                     46:             else {
                     47:                 if ( -d $options ) {
                     48:                     $self->_path_to( 'todo_dir', $options );
                     49:                 }
                     50:                 elsif ( $options =~ /\.txt$/ixms ) {
                     51:                     $self->_path_to( 'todo_file', $options );
                     52:                 }
                     53:                 else {
                     54:                     carp "Unknown options [$options]";
                     55:                 }
                     56:             }
                     57:         }
                     58:
                     59:         my $file = $self->_path_to('todo_file');
                     60:         if ( defined $file && -e $file ) {
                     61:             $self->load();
                     62:         }
1.2       andrew     63:
                     64:         return $self;
                     65:     }
                     66:
1.5       andrew     67:     sub _path_to {
                     68:         my ( $self, $type, $path ) = @_;
                     69:         my $ident = ident($self);
                     70:
                     71:         if ( $type eq 'todo_dir' ) {
                     72:             if ($path) {
                     73:                 $path_of{$ident}{$type} = $path;
                     74:             }
                     75:             return $path_of{$ident}{$type};
                     76:         }
                     77:
                     78:         if ($path) {
                     79:             my ( $volume, $directories, $file )
                     80:                 = File::Spec->splitpath($path);
                     81:             $path_of{$ident}{$type} = $file;
                     82:
                     83:             if ($volume) {
                     84:                 $directories = File::Spec->catdir( $volume, $directories );
                     85:             }
                     86:
                     87:             # XXX Should we save complete paths to each file, mebbe only if
                     88:             # the dirs are different?
                     89:             if ($directories) {
                     90:                 $path_of{$ident}{todo_dir} = $directories;
                     91:             }
                     92:         }
                     93:
                     94:         if ( $type =~ /(todo|done|report)_file/xms ) {
                     95:             if ( my ( $pre, $post )
                     96:                 = $path_of{$ident}{$type} =~ /^(.*)$1(.*)\.txt$/ixms )
                     97:             {
                     98:                 foreach my $f qw( todo done report ) {
                     99:                     if ( !defined $path_of{$ident}{ $f . '_file' } ) {
                    100:                         $path_of{$ident}{ $f . '_file' }
                    101:                             = $pre . $f . $post . '.txt';
                    102:                     }
                    103:                 }
                    104:             }
                    105:         }
                    106:
                    107:         if ( defined $path_of{$ident}{todo_dir} ) {
                    108:             return File::Spec->catfile( $path_of{$ident}{todo_dir},
                    109:                 $path_of{$ident}{$type} );
                    110:         }
                    111:
                    112:         return;
                    113:     }
                    114:
1.3       andrew    115:     sub file {
1.2       andrew    116:         my ( $self, $file ) = @_;
                    117:         my $ident = ident($self);
                    118:
1.5       andrew    119:         if ( defined $file && exists $path_of{$ident}{$file} ) {
                    120:             $file = $self->_path_to($file);
                    121:         }
                    122:         else {
                    123:             $file = $self->_path_to( 'todo_file', $file );
1.2       andrew    124:         }
                    125:
1.5       andrew    126:         return $file;
1.3       andrew    127:     }
                    128:
                    129:     sub load {
                    130:         my ( $self, $file ) = @_;
                    131:         my $ident = ident($self);
                    132:
1.5       andrew    133:         $file = $self->file($file);
                    134:
                    135:         if ( !defined $file ) {
1.6     ! andrew    136:             croak q{todo file can't be found};
1.5       andrew    137:         }
                    138:
                    139:         if ( !-e $file ) {
                    140:             carp "todo file [$file] does not exist";
                    141:             return;
                    142:         }
1.2       andrew    143:
                    144:         my @list;
1.5       andrew    145:         my $line = 1;
1.2       andrew    146:         open my $fh, '<', $file or croak "Couldn't open [$file]: $!";
                    147:         while (<$fh>) {
                    148:             s/\r?\n$//xms;
                    149:             push @list, Text::Todo::Entry->new($_);
                    150:         }
                    151:         close $fh or croak "Couldn't close [$file]: $!";
                    152:         $list_of{$ident} = \@list;
                    153:
                    154:         return 1;
                    155:     }
                    156:
                    157:     sub save {
                    158:         my ( $self, $file ) = @_;
                    159:         my $ident = ident($self);
                    160:
1.5       andrew    161:         $file = $self->file($file);
                    162:         if ( !defined $file ) {
1.6     ! andrew    163:             croak q{todo file can't be found};
1.5       andrew    164:         }
1.2       andrew    165:
                    166:         open my $fh, '>', $file or croak "Couldn't open [$file]: $!";
                    167:         foreach my $e ( @{ $list_of{$ident} } ) {
1.3       andrew    168:             print {$fh} $e->text . "\n"
                    169:                 or croak "Couldn't print to [$file]: $!";
1.2       andrew    170:         }
                    171:         close $fh or croak "Couldn't close [$file]: $!";
                    172:
                    173:         return 1;
                    174:     }
                    175:
                    176:     sub list {
1.3       andrew    177:         my ($self) = @_;
1.2       andrew    178:         my $ident = ident($self);
1.6     ! andrew    179:
1.2       andrew    180:         return if !$list_of{$ident};
1.6     ! andrew    181:         return wantarray ? @{ $list_of{$ident} } : $list_of{$ident};
1.5       andrew    182:     }
                    183:
                    184:     sub listpri {
                    185:         my ($self) = @_;
                    186:
                    187:         my @list = grep { $_->priority } $self->list;
                    188:
                    189:         return wantarray ? @list : \@list;
1.2       andrew    190:     }
1.1       andrew    191:
1.3       andrew    192:     sub add {
                    193:         my ( $self, $entry ) = @_;
                    194:         my $ident = ident($self);
                    195:
1.5       andrew    196:         if ( !ref $entry ) {
                    197:             $entry = Text::Todo::Entry->new($entry);
                    198:         }
                    199:         elsif ( ref $entry ne 'Text::Todo::Entry' ) {
                    200:             croak(
                    201:                 'entry is a ' . ref($entry) . ' not a Text::Todo::Entry!' );
                    202:         }
                    203:
                    204:         push @{ $list_of{$ident} }, $entry;
                    205:
                    206:         return $entry;
                    207:     }
                    208:
1.6     ! andrew    209:     sub del {
1.5       andrew    210:         my ( $self, $src ) = @_;
                    211:         my $ident = ident($self);
                    212:
1.6     ! andrew    213:         my $id = $self->_find_entry_id($src);
1.5       andrew    214:
                    215:         my @list = $self->list;
1.6     ! andrew    216:         my $entry = splice @list, $id, 1;
1.5       andrew    217:         $list_of{$ident} = \@list;
                    218:
                    219:         return $entry;
                    220:     }
                    221:
                    222:     sub move {
                    223:         my ( $self, $entry, $dst ) = @_;
                    224:         my $ident = ident($self);
                    225:
                    226:         my $src  = $self->_find_entry_id($entry);
                    227:         my @list = $self->list;
                    228:
1.6     ! andrew    229:         splice @list, $dst, 0, splice @list, $src, 1;
1.5       andrew    230:
                    231:         $list_of{$ident} = \@list;
                    232:
                    233:         return 1;
                    234:     }
                    235:
1.6     ! andrew    236:     sub listproj {
1.5       andrew    237:         my ( $self, $entry, $dst ) = @_;
                    238:         my $ident = ident($self);
                    239:
                    240:         my %available_projects;
1.6     ! andrew    241:         foreach my $e ( $self->list ) {
1.5       andrew    242:             foreach my $p ( $e->projects ) {
                    243:                 $available_projects{$p} = 1;
                    244:             }
                    245:         }
                    246:
                    247:         my @projects = sort keys %available_projects;
                    248:
                    249:         return wantarray ? @projects : \@projects;
                    250:     }
                    251:
1.6     ! andrew    252:     sub archive  { carp "unsupported\n"; return }
        !           253:     sub addto    { carp "unsupported\n"; return }
        !           254:     sub listfile { carp "unsupported\n"; return }
1.5       andrew    255:
                    256:     sub _find_entry_id {
                    257:         my ( $self, $entry ) = @_;
                    258:         my $ident = ident($self);
                    259:
1.3       andrew    260:         if ( ref $entry ) {
                    261:             if ( ref $entry ne 'Text::Todo::Entry' ) {
                    262:                 croak(    'entry is a '
                    263:                         . ref($entry)
                    264:                         . ' not a Text::Todo::Entry!' );
                    265:             }
1.5       andrew    266:
                    267:             my @list = $self->list;
                    268:             foreach my $id ( 0 .. $#list ) {
                    269:                 if ( $list[$id] eq $entry ) {
                    270:                     return $id;
                    271:                 }
                    272:             }
1.3       andrew    273:         }
1.5       andrew    274:         elsif ( $entry =~ /^\d+$/xms ) {
                    275:             return $entry;
1.3       andrew    276:         }
                    277:
1.5       andrew    278:         croak "Invalid entry [$entry]!";
1.3       andrew    279:     }
1.2       andrew    280: }
1.1       andrew    281:
1.2       andrew    282: 1;    # Magic true value required at end of module
1.1       andrew    283: __END__
                    284:
                    285: =head1 NAME
                    286:
1.4       andrew    287: Text::Todo - Perl interface to todo_txt files
1.1       andrew    288:
1.6     ! andrew    289: =head1 VERSION
        !           290:
        !           291: I will have to figure out how to include $VERSION in this somehow.
        !           292:
        !           293: Perhaps RCS Id is good enough?
        !           294:
        !           295:     $Id$
1.1       andrew    296:
                    297: =head1 SYNOPSIS
                    298:
                    299:     use Text::Todo;
                    300:
                    301: =head1 DESCRIPTION
                    302:
1.4       andrew    303: For more information see L<http://todotxt.com>
1.1       andrew    304:
                    305: =head1 INTERFACE
                    306:
1.2       andrew    307: =head2 new
                    308:
                    309: =head2 load
                    310:
                    311: =head2 save
                    312:
1.3       andrew    313: =head2 file
                    314:
1.2       andrew    315: =head2 list
1.3       andrew    316:
                    317: =head2 add
1.1       andrew    318:
                    319: =head1 DIAGNOSTICS
                    320:
                    321: =for author to fill in:
                    322:     List every single error and warning message that the module can
                    323:     generate (even the ones that will "never happen"), with a full
                    324:     explanation of each problem, one or more likely causes, and any
                    325:     suggested remedies.
                    326:
                    327: =over
                    328:
                    329: =item C<< Error message here, perhaps with %s placeholders >>
                    330:
                    331: [Description of error here]
                    332:
                    333: =item C<< Another error message here >>
                    334:
                    335: [Description of error here]
                    336:
                    337: [Et cetera, et cetera]
                    338:
                    339: =back
                    340:
                    341:
                    342: =head1 CONFIGURATION AND ENVIRONMENT
                    343:
                    344: Text::Todo requires no configuration files or environment variables.
                    345:
1.4       andrew    346: Someday it should be able to read and use the todo.sh config file.
                    347:
1.1       andrew    348:
                    349: =head1 DEPENDENCIES
                    350:
                    351: =for author to fill in:
                    352:     A list of all the other modules that this module relies upon,
                    353:     including any restrictions on versions, and an indication whether
                    354:     the module is part of the standard Perl distribution, part of the
                    355:     module's distribution, or must be installed separately. ]
                    356:
                    357: None.
                    358:
                    359:
                    360: =head1 INCOMPATIBILITIES
                    361:
                    362: None reported.
                    363:
                    364:
                    365: =head1 BUGS AND LIMITATIONS
                    366:
                    367: No bugs have been reported.
                    368:
                    369: Please report any bugs or feature requests to
                    370: C<bug-text-todo@rt.cpan.org>, or through the web interface at
                    371: L<http://rt.cpan.org>.
                    372:
                    373:
                    374: =head1 AUTHOR
                    375:
                    376: Andrew Fresh  C<< <andrew@cpan.org> >>
                    377:
                    378:
                    379: =head1 LICENSE AND COPYRIGHT
                    380:
                    381: Copyright (c) 2009, Andrew Fresh C<< <andrew@cpan.org> >>. All rights reserved.
                    382:
                    383: This module is free software; you can redistribute it and/or
                    384: modify it under the same terms as Perl itself. See L<perlartistic>.
                    385:
                    386:
                    387: =head1 DISCLAIMER OF WARRANTY
                    388:
                    389: BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
                    390: FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
                    391: OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
                    392: PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
                    393: EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                    394: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
                    395: ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
                    396: YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
                    397: NECESSARY SERVICING, REPAIR, OR CORRECTION.
                    398:
                    399: IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
                    400: WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
                    401: REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
                    402: LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
                    403: OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
                    404: THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
                    405: RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
                    406: FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
                    407: SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
                    408: SUCH DAMAGES.

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>