[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.27

1.1       andrew      1: package Text::Todo;
                      2:
1.27    ! andrew      3: # $AFresh1: Todo.pm,v 1.26 2010/02/14 06:08:07 andrew Exp $
1.1       andrew      4:
                      5: use warnings;
                      6: use strict;
                      7: use Carp;
                      8:
1.19      andrew      9: use Class::Std::Utils;
1.2       andrew     10: use Text::Todo::Entry;
1.5       andrew     11: use File::Spec;
                     12:
1.27    ! andrew     13: use version; our $VERSION = qv('0.2.0');
1.1       andrew     14:
1.2       andrew     15: {
                     16:
1.20      andrew     17:     my @attr_refs = \(
                     18:         my %path_of,
                     19:
                     20:         my %list_of,
                     21:         my %loaded_of,
1.25      andrew     22:         my %known_tags_of,
1.20      andrew     23:     );
1.19      andrew     24:
                     25:     sub new {
                     26:         my ( $class, $options ) = @_;
                     27:
                     28:         my $self = bless anon_scalar(), $class;
                     29:         my $ident = ident($self);
1.2       andrew     30:
1.5       andrew     31:         $path_of{$ident} = {
1.14      andrew     32:             todo_dir  => undef,
                     33:             todo_file => 'todo.txt',
                     34:             done_file => undef,
1.5       andrew     35:         };
                     36:
1.26      andrew     37:         my %tags = (
                     38:             context => q{@},
                     39:             project => q{+},
                     40:         );
1.25      andrew     41:
1.5       andrew     42:         if ($options) {
                     43:             if ( ref $options eq 'HASH' ) {
                     44:                 foreach my $opt ( keys %{$options} ) {
                     45:                     if ( exists $path_of{$ident}{$opt} ) {
                     46:                         $self->_path_to( $opt, $options->{$opt} );
                     47:                     }
1.26      andrew     48:                     elsif ( $opt eq 'tags'
                     49:                         && ref $options->{$opt} eq 'HASH' )
                     50:                     {
                     51:                         %tags = ( %tags, %{ $options->{$opt} } );
1.25      andrew     52:                     }
1.5       andrew     53:                     else {
1.14      andrew     54:
1.13      andrew     55:                         #carp "Invalid option [$opt]";
1.5       andrew     56:                     }
                     57:                 }
                     58:             }
                     59:             else {
                     60:                 if ( -d $options ) {
                     61:                     $self->_path_to( 'todo_dir', $options );
                     62:                 }
                     63:                 elsif ( $options =~ /\.txt$/ixms ) {
                     64:                     $self->_path_to( 'todo_file', $options );
                     65:                 }
                     66:                 else {
                     67:                     carp "Unknown options [$options]";
                     68:                 }
                     69:             }
                     70:         }
                     71:
1.26      andrew     72:         $known_tags_of{$ident} = \%tags;
                     73:
1.5       andrew     74:         my $file = $self->_path_to('todo_file');
                     75:         if ( defined $file && -e $file ) {
                     76:             $self->load();
                     77:         }
1.2       andrew     78:
                     79:         return $self;
                     80:     }
                     81:
1.5       andrew     82:     sub _path_to {
                     83:         my ( $self, $type, $path ) = @_;
                     84:         my $ident = ident($self);
                     85:
                     86:         if ( $type eq 'todo_dir' ) {
                     87:             if ($path) {
                     88:                 $path_of{$ident}{$type} = $path;
                     89:             }
                     90:             return $path_of{$ident}{$type};
                     91:         }
                     92:
                     93:         if ($path) {
                     94:             my ( $volume, $directories, $file )
                     95:                 = File::Spec->splitpath($path);
                     96:             $path_of{$ident}{$type} = $file;
                     97:
                     98:             if ($volume) {
                     99:                 $directories = File::Spec->catdir( $volume, $directories );
                    100:             }
                    101:
                    102:             # XXX Should we save complete paths to each file, mebbe only if
                    103:             # the dirs are different?
                    104:             if ($directories) {
                    105:                 $path_of{$ident}{todo_dir} = $directories;
                    106:             }
                    107:         }
                    108:
                    109:         if ( $type =~ /(todo|done|report)_file/xms ) {
                    110:             if ( my ( $pre, $post )
                    111:                 = $path_of{$ident}{$type} =~ /^(.*)$1(.*)\.txt$/ixms )
                    112:             {
                    113:                 foreach my $f qw( todo done report ) {
                    114:                     if ( !defined $path_of{$ident}{ $f . '_file' } ) {
                    115:                         $path_of{$ident}{ $f . '_file' }
                    116:                             = $pre . $f . $post . '.txt';
                    117:                     }
                    118:                 }
                    119:             }
                    120:         }
                    121:
                    122:         if ( defined $path_of{$ident}{todo_dir} ) {
                    123:             return File::Spec->catfile( $path_of{$ident}{todo_dir},
                    124:                 $path_of{$ident}{$type} );
                    125:         }
                    126:
                    127:         return;
                    128:     }
                    129:
1.3       andrew    130:     sub file {
1.2       andrew    131:         my ( $self, $file ) = @_;
                    132:         my $ident = ident($self);
                    133:
1.5       andrew    134:         if ( defined $file && exists $path_of{$ident}{$file} ) {
                    135:             $file = $self->_path_to($file);
                    136:         }
                    137:         else {
                    138:             $file = $self->_path_to( 'todo_file', $file );
1.2       andrew    139:         }
                    140:
1.5       andrew    141:         return $file;
1.3       andrew    142:     }
                    143:
                    144:     sub load {
                    145:         my ( $self, $file ) = @_;
                    146:         my $ident = ident($self);
                    147:
1.8       andrew    148:         $loaded_of{$ident} = undef;
                    149:
1.9       andrew    150:         $file = $self->file($file);
                    151:
1.8       andrew    152:         if ( $list_of{$ident} = $self->listfile($file) ) {
1.26      andrew    153:             $self->known_tags;
1.8       andrew    154:             $loaded_of{$ident} = $file;
                    155:             return 1;
                    156:         }
                    157:
                    158:         return;
                    159:     }
                    160:
                    161:     sub listfile {
                    162:         my ( $self, $file ) = @_;
                    163:
1.5       andrew    164:         $file = $self->file($file);
                    165:
                    166:         if ( !defined $file ) {
1.8       andrew    167:             carp q{file can't be found};
                    168:             return;
1.5       andrew    169:         }
                    170:
                    171:         if ( !-e $file ) {
1.8       andrew    172:             carp "file [$file] does not exist";
1.5       andrew    173:             return;
                    174:         }
1.2       andrew    175:
                    176:         my @list;
                    177:         open my $fh, '<', $file or croak "Couldn't open [$file]: $!";
                    178:         while (<$fh>) {
                    179:             s/\r?\n$//xms;
1.19      andrew    180:             push @list, Text::Todo::Entry->new($_);
1.2       andrew    181:         }
                    182:         close $fh or croak "Couldn't close [$file]: $!";
                    183:
1.8       andrew    184:         return wantarray ? @list : \@list;
1.2       andrew    185:     }
                    186:
                    187:     sub save {
                    188:         my ( $self, $file ) = @_;
                    189:         my $ident = ident($self);
                    190:
1.5       andrew    191:         $file = $self->file($file);
                    192:         if ( !defined $file ) {
1.6       andrew    193:             croak q{todo file can't be found};
1.5       andrew    194:         }
1.2       andrew    195:
                    196:         open my $fh, '>', $file or croak "Couldn't open [$file]: $!";
                    197:         foreach my $e ( @{ $list_of{$ident} } ) {
1.3       andrew    198:             print {$fh} $e->text . "\n"
                    199:                 or croak "Couldn't print to [$file]: $!";
1.2       andrew    200:         }
                    201:         close $fh or croak "Couldn't close [$file]: $!";
                    202:
1.9       andrew    203:         $loaded_of{$ident} = $file;
                    204:
1.2       andrew    205:         return 1;
                    206:     }
                    207:
                    208:     sub list {
1.3       andrew    209:         my ($self) = @_;
1.2       andrew    210:         my $ident = ident($self);
1.6       andrew    211:
1.2       andrew    212:         return if !$list_of{$ident};
1.6       andrew    213:         return wantarray ? @{ $list_of{$ident} } : $list_of{$ident};
1.5       andrew    214:     }
                    215:
                    216:     sub listpri {
1.14      andrew    217:         my ( $self, $pri ) = @_;
1.5       andrew    218:
1.14      andrew    219:         my @list;
                    220:         if ($pri) {
                    221:             $pri = uc $pri;
                    222:             if ( $pri !~ /^[A-Z]$/xms ) {
1.17      andrew    223:                 croak 'PRIORITY must a single letter from A to Z.';
1.14      andrew    224:             }
                    225:             @list = grep { defined $_->priority && $_->priority eq $pri }
                    226:                 $self->list;
                    227:         }
                    228:         else {
                    229:             @list = grep { $_->priority } $self->list;
                    230:         }
1.5       andrew    231:
                    232:         return wantarray ? @list : \@list;
1.2       andrew    233:     }
1.1       andrew    234:
1.3       andrew    235:     sub add {
                    236:         my ( $self, $entry ) = @_;
                    237:         my $ident = ident($self);
                    238:
1.5       andrew    239:         if ( !ref $entry ) {
1.25      andrew    240:             $entry = Text::Todo::Entry->new(
                    241:                 {   text => $entry,
1.26      andrew    242:                     tags => $known_tags_of{$ident},
1.25      andrew    243:                 }
                    244:             );
1.5       andrew    245:         }
                    246:         elsif ( ref $entry ne 'Text::Todo::Entry' ) {
                    247:             croak(
                    248:                 'entry is a ' . ref($entry) . ' not a Text::Todo::Entry!' );
                    249:         }
                    250:
                    251:         push @{ $list_of{$ident} }, $entry;
                    252:
1.26      andrew    253:         $self->known_tags;
                    254:
1.5       andrew    255:         return $entry;
                    256:     }
                    257:
1.6       andrew    258:     sub del {
1.5       andrew    259:         my ( $self, $src ) = @_;
                    260:         my $ident = ident($self);
                    261:
1.6       andrew    262:         my $id = $self->_find_entry_id($src);
1.5       andrew    263:
                    264:         my @list = $self->list;
1.6       andrew    265:         my $entry = splice @list, $id, 1;
1.5       andrew    266:         $list_of{$ident} = \@list;
                    267:
                    268:         return $entry;
                    269:     }
                    270:
                    271:     sub move {
                    272:         my ( $self, $entry, $dst ) = @_;
                    273:         my $ident = ident($self);
                    274:
                    275:         my $src  = $self->_find_entry_id($entry);
                    276:         my @list = $self->list;
                    277:
1.6       andrew    278:         splice @list, $dst, 0, splice @list, $src, 1;
1.5       andrew    279:
                    280:         $list_of{$ident} = \@list;
                    281:
                    282:         return 1;
                    283:     }
                    284:
1.6       andrew    285:     sub listproj {
1.17      andrew    286:         my ($self) = @_;
1.14      andrew    287:         return $self->listtag('project');
                    288:     }
                    289:
                    290:     sub listcon {
1.17      andrew    291:         my ($self) = @_;
1.14      andrew    292:         return $self->listtag('context');
                    293:     }
                    294:
                    295:     sub listtag {
                    296:         my ( $self, $tag ) = @_;
1.5       andrew    297:         my $ident = ident($self);
1.17      andrew    298:
1.14      andrew    299:         my $accessor = $tag . 's';
1.5       andrew    300:
1.14      andrew    301:         my %available;
1.6       andrew    302:         foreach my $e ( $self->list ) {
1.14      andrew    303:             foreach my $p ( $e->$accessor ) {
                    304:                 $available{$p} = 1;
1.5       andrew    305:             }
                    306:         }
                    307:
1.14      andrew    308:         my @tags = sort keys %available;
1.5       andrew    309:
1.17      andrew    310:         return wantarray ? @tags : \@tags;
1.5       andrew    311:     }
                    312:
1.26      andrew    313:     sub learn_tag {
                    314:         my ( $self, $tag, $sigal ) = @_;
                    315:
                    316:         $known_tags_of{ ident $self}{$tag} = $sigal;
                    317:         $self->known_tags;
                    318:
                    319:         return 1;
                    320:     }
                    321:
                    322:     sub known_tags {
1.25      andrew    323:         my ($self) = @_;
                    324:         my $ident = ident($self);
                    325:
                    326:         my @list = $self->list;
1.26      andrew    327:         my %tags = %{ $known_tags_of{$ident} };
1.25      andrew    328:
                    329:         foreach my $e (@list) {
                    330:             my $kt = $e->known_tags;
                    331:             foreach my $t ( keys %{$kt} ) {
1.26      andrew    332:                 if ( !exists $tags{$t} ) {
                    333:                     $tags{$t} = $kt->{$t};
1.25      andrew    334:                 }
                    335:             }
                    336:         }
                    337:
1.26      andrew    338:         foreach my $e (@list) {
                    339:             my $kt = $e->known_tags;
                    340:             foreach my $t ( keys %tags ) {
                    341:                 if ( !exists $kt->{$t} || $tags{$t} ne $kt->{$t} ) {
                    342:                     $e->learn_tag( $t, $tags{$t} );
                    343:                 }
                    344:             }
                    345:         }
1.25      andrew    346:
1.26      andrew    347:         $known_tags_of{$ident} = \%tags;
1.25      andrew    348:
1.26      andrew    349:         return $known_tags_of{$ident};
1.25      andrew    350:     }
                    351:
1.9       andrew    352:     sub archive {
                    353:         my ($self) = @_;
                    354:         my $ident = ident($self);
                    355:
                    356:         if ( !defined $loaded_of{$ident}
                    357:             || $loaded_of{$ident} ne $self->file('todo_file') )
                    358:         {
                    359:             carp 'todo_file not loaded';
                    360:             return;
                    361:         }
                    362:
1.12      andrew    363:         my $changed = 0;
1.9       andrew    364:     ENTRY: foreach my $e ( $self->list ) {
                    365:             if ( $e->done ) {
                    366:                 if ( $self->addto( 'done_file', $e ) && $self->del($e) ) {
1.12      andrew    367:                     $changed++;
1.9       andrew    368:                 }
                    369:                 else {
                    370:                     carp q{Couldn't archive entry [} . $e->text . ']';
                    371:                     last ENTRY;
                    372:                 }
                    373:             }
1.14      andrew    374:             elsif ( $e->text eq q{} ) {
                    375:                 if ( $self->del($e) ) {
1.12      andrew    376:                     $changed++;
                    377:                 }
                    378:                 else {
                    379:                     carp q{Couldn't delete blank entry};
                    380:                     last ENTRY;
                    381:                 }
                    382:             }
1.9       andrew    383:         }
                    384:
1.12      andrew    385:         if ($changed) {
1.9       andrew    386:             $self->save;
                    387:         }
                    388:
1.12      andrew    389:         return $changed;
1.9       andrew    390:     }
1.8       andrew    391:
                    392:     sub addto {
                    393:         my ( $self, $file, $entry ) = @_;
                    394:         my $ident = ident($self);
                    395:
                    396:         $file = $self->file($file);
                    397:         if ( !defined $file ) {
                    398:             croak q{file can't be found};
                    399:         }
                    400:
1.9       andrew    401:         if ( ref $entry ) {
                    402:             if ( ref $entry eq 'Text::Todo::Entry' ) {
                    403:                 $entry = $entry->text;
                    404:             }
                    405:             else {
                    406:                 carp 'Unknown ref [' . ref($entry) . ']';
                    407:                 return;
                    408:             }
                    409:         }
                    410:
1.8       andrew    411:         open my $fh, '>>', $file or croak "Couldn't open [$file]: $!";
                    412:         print {$fh} $entry, "\n"
                    413:             or croak "Couldn't print to [$file]: $!";
                    414:         close $fh or croak "Couldn't close [$file]: $!";
                    415:
                    416:         if ( defined $loaded_of{$ident} && $file eq $loaded_of{$ident} ) {
                    417:             return $self->load($file);
                    418:         }
                    419:
                    420:         return 1;
                    421:     }
1.5       andrew    422:
                    423:     sub _find_entry_id {
                    424:         my ( $self, $entry ) = @_;
                    425:         my $ident = ident($self);
                    426:
1.3       andrew    427:         if ( ref $entry ) {
                    428:             if ( ref $entry ne 'Text::Todo::Entry' ) {
                    429:                 croak(    'entry is a '
                    430:                         . ref($entry)
                    431:                         . ' not a Text::Todo::Entry!' );
                    432:             }
1.5       andrew    433:
                    434:             my @list = $self->list;
                    435:             foreach my $id ( 0 .. $#list ) {
                    436:                 if ( $list[$id] eq $entry ) {
                    437:                     return $id;
                    438:                 }
                    439:             }
1.3       andrew    440:         }
1.5       andrew    441:         elsif ( $entry =~ /^\d+$/xms ) {
                    442:             return $entry;
1.3       andrew    443:         }
                    444:
1.5       andrew    445:         croak "Invalid entry [$entry]!";
1.3       andrew    446:     }
1.20      andrew    447:
                    448:     sub DESTROY {
                    449:         my ($self) = @_;
                    450:         my $ident = ident $self;
1.21      andrew    451:
1.20      andrew    452:         foreach my $attr_ref (@attr_refs) {
                    453:             delete $attr_ref->{$ident};
                    454:         }
1.21      andrew    455:
                    456:         return;
1.20      andrew    457:     }
1.2       andrew    458: }
1.1       andrew    459:
1.2       andrew    460: 1;    # Magic true value required at end of module
1.1       andrew    461: __END__
                    462:
                    463: =head1 NAME
                    464:
1.24      andrew    465: Text::Todo - Perl interface to todotxt files
1.1       andrew    466:
1.10      andrew    467:
1.6       andrew    468: =head1 VERSION
                    469:
1.10      andrew    470: Since the $VERSION can't be automatically included,
                    471: here is the RCS Id instead, you'll have to look up $VERSION.
1.6       andrew    472:
1.27    ! andrew    473:     $Id: Todo.pm,v 1.26 2010/02/14 06:08:07 andrew Exp $
1.1       andrew    474:
                    475: =head1 SYNOPSIS
                    476:
                    477:     use Text::Todo;
1.10      andrew    478:
                    479:     my $todo = Text::Todo->new('todo/todo.txt');
                    480:
                    481:     foreach my $e (sort { lc($_->text) cmp lc($e->text)} $todo->list) {
                    482:         print $e->text, "\n";
                    483:     }
                    484:
1.1       andrew    485:
                    486: =head1 DESCRIPTION
                    487:
1.10      andrew    488: This module is a basic interface to the todo.txt files as described by
                    489: Lifehacker and extended by members of their community.
                    490:
1.4       andrew    491: For more information see L<http://todotxt.com>
1.1       andrew    492:
1.10      andrew    493: This module supports the 3 axes of an effective todo list.
                    494: Priority, Project and Context.
                    495:
                    496: It does not support other notations or many of the more advanced features of
                    497: the todo.sh like plugins.
                    498:
                    499: It should be extensible, but and hopefully will be before a 1.0 release.
                    500:
                    501:
1.1       andrew    502: =head1 INTERFACE
                    503:
1.19      andrew    504: =head2 new
1.2       andrew    505:
1.10      andrew    506:     new({
                    507:         [ todo_dir    => 'directory', ]
                    508:         [ todo_file   => 'filename in todo_dir', ]
                    509:         [ done_file   => 'filename in todo_dir', ]
                    510:         [ report_file => 'filename in todo_dir', ]
                    511:         });
                    512:
                    513: Allows you to set each item individually.  todo_file defaults to todo.txt.
                    514:
1.19      andrew    515:     new('path/to/todo.txt');
1.10      andrew    516:
                    517: Automatically sets todo_dir to 'path/to', todo_file to 'todo.txt'
                    518:
1.19      andrew    519:     new('path/to')
                    520:
                    521: If you pass an existing directory to new, it will set todo_dir.
                    522:
                    523:
1.10      andrew    524: If you what you set matches (.*)todo(.*).txt it will automatically set
                    525: done_file to $1done$2.txt
                    526: and
                    527: report_file to $1report$2.txt.
                    528:
                    529: For example, new('todo/todo.shopping.txt') will set
                    530: todo_dir to 'todo',
                    531: todo_file to 'todo.shopping.txt',
                    532: done_file to 'done.shopping.txt',
                    533: and
                    534: report_file to 'report.shopping.txt'.
                    535:
1.9       andrew    536: =head2 file
                    537:
1.10      andrew    538: Allows you to read the paths to the files in use.
                    539: If as in the SYNOPSIS above you used $todo = new('todo/todo.txt').
                    540:
                    541:     $todo_file = $todo->file('todo_file');
                    542:
                    543: then, $todo_file eq 'todo/todo.txt'
                    544:
1.2       andrew    545: =head2 load
1.16      andrew    546: - Reads a list from a file into the current object.
1.2       andrew    547:
1.10      andrew    548: Allows you to load a different file into the object.
                    549:
                    550:     $todo->load('done_file');
                    551:
                    552: This effects the other functions that act on the list.
                    553:
1.2       andrew    554: =head2 save
1.16      andrew    555: - Writes the list to disk.
1.2       andrew    556:
1.10      andrew    557:     $todo->save(['new/path/to/todo']);
                    558:
1.16      andrew    559: Either writes the current working file or the passed in argument
1.10      andrew    560: that can be recognized by file().
                    561:
                    562: If you specify a filename it will save to that file and update the paths.
                    563: Additional changes to the object work on that file.
                    564:
1.9       andrew    565: =head2 list
1.16      andrew    566: - get the curently loaded list
1.9       andrew    567:
1.10      andrew    568:     my @todo_list = $todo->list;
                    569:
1.16      andrew    570: In list context returns a list, it scalar context returns an array reference to the list.
                    571:
1.9       andrew    572: =head2 listpri
1.16      andrew    573: - get the list items that are marked priority
1.3       andrew    574:
1.10      andrew    575: Like list, but only returns entries that have priority set.
                    576:
                    577:     my @priority_list = $todo->listpri;
                    578:
1.16      andrew    579: Since this is so easy to write as:
                    580:
                    581:     my @priority_list = grep { $_->priority } $todo->list;
                    582:
                    583: I think it may become depreciated unless there is demand.
                    584:
1.26      andrew    585: =head2 known_tags
                    586:
                    587: Returns a reference to a hash of the tags known to the list.
                    588:
                    589: =head2 learn_tag($tag, $sigal)
1.25      andrew    590:
1.26      andrew    591: Let the entire list learn a new tag.
                    592: If you are working with a list you should use this instead of
                    593: $entry->learn_tag because it will update all entries.
1.25      andrew    594:
                    595: =head2 listtag($tag)
1.16      andrew    596:
                    597: Returns tags found in the list sorted by name.
1.3       andrew    598:
1.16      andrew    599: If there were projects +GarageSale and +Shopping then
1.10      andrew    600:
1.16      andrew    601:     my @projects = $todo->listtag('project');
1.10      andrew    602:
                    603: is the same as
                    604:
                    605:     @projects = ( 'GarageSale', 'Shopping' );
1.16      andrew    606:
                    607: =head2 listcon
                    608: - Shortcut to listtag('context')
                    609:
                    610: =head2 listproj
                    611: - Shortcut to listtag('project')
1.10      andrew    612:
1.3       andrew    613: =head2 add
1.9       andrew    614:
1.10      andrew    615: Adds a new entry to the list.
                    616: Can either be a Text::Todo::Entry object or plain text.
                    617:
                    618:     $todo->add('new todo entry');
                    619:
                    620: It then becomes $todo->list->[-1];
                    621:
1.9       andrew    622: =head2 del
                    623:
1.10      andrew    624: Remove an entry from the list, either the reference or by number.
                    625:
                    626:     $removed_entry = $todo->del($entry);
                    627:
                    628: $entry can either be an Text::Todo::Entry in the list or the index of the
                    629: entry to delete.
                    630:
                    631: Note that entries are 0 indexed (as expected in perl) not starting at line 1.
                    632:
1.9       andrew    633: =head2 move
                    634:
1.10      andrew    635:     $todo->move($entry, $new_pos);
                    636:
                    637: $entry can either be the number of the entry or the actual entry.
                    638: $new_pos is the new position to put it.
                    639:
                    640: Note that entries are 0 indexed (as expected in perl) not starting at line 1.
                    641:
1.9       andrew    642: =head2 archive
                    643:
1.10      andrew    644:     $todo->archive
                    645:
                    646: Iterates over the list and for each done entry,
                    647: addto('done_file')
                    648: and
                    649: del($entry).
                    650: If any were archived it will then
                    651: save()
                    652: and
                    653: load().
                    654:
1.9       andrew    655: =head2 addto
                    656:
1.10      andrew    657:     $todo->addto($file, $entry);
1.1       andrew    658:
1.10      andrew    659: Appends text to the file.
                    660: $file can be anyting recognized by file().
                    661: $entry can either be a Text::Todo::Entry or plain text.
1.1       andrew    662:
1.10      andrew    663: =head2 listfile
1.1       andrew    664:
1.10      andrew    665:     @list = $todo->listfile($file);
1.1       andrew    666:
1.10      andrew    667: Read a file and returns a list like $todo->list but does not update the
                    668: internal list that is being worked with.
                    669: $file can be anyting recognized by file().
1.1       andrew    670:
                    671:
1.10      andrew    672: =head1 DIAGNOSTICS
1.1       andrew    673:
1.10      andrew    674: Most methods return undef on failure.
1.1       andrew    675:
1.10      andrew    676: Some more important methods are fatal.
1.1       andrew    677:
                    678:
                    679: =head1 CONFIGURATION AND ENVIRONMENT
                    680:
                    681: Text::Todo requires no configuration files or environment variables.
                    682:
1.10      andrew    683: Someday it should be able to read and use the todo.sh config file.  This may
                    684: possibly be better done in a client that would use this module.
1.4       andrew    685:
1.1       andrew    686:
                    687: =head1 DEPENDENCIES
                    688:
1.19      andrew    689: Class::Std::Utils
1.10      andrew    690: File::Spec
                    691: version
1.1       andrew    692:
                    693:
                    694: =head1 INCOMPATIBILITIES
                    695:
                    696: None reported.
                    697:
                    698:
                    699: =head1 BUGS AND LIMITATIONS
                    700:
                    701: No bugs have been reported.
1.11      andrew    702:
                    703: Limitations:
                    704:
                    705: Currently there isn't an easy way to print out line numbers with the entry.
1.1       andrew    706:
                    707: Please report any bugs or feature requests to
                    708: C<bug-text-todo@rt.cpan.org>, or through the web interface at
                    709: L<http://rt.cpan.org>.
                    710:
                    711:
                    712: =head1 AUTHOR
                    713:
                    714: Andrew Fresh  C<< <andrew@cpan.org> >>
                    715:
                    716:
                    717: =head1 LICENSE AND COPYRIGHT
                    718:
                    719: Copyright (c) 2009, Andrew Fresh C<< <andrew@cpan.org> >>. All rights reserved.
                    720:
                    721: This module is free software; you can redistribute it and/or
                    722: modify it under the same terms as Perl itself. See L<perlartistic>.
                    723:
                    724:
                    725: =head1 DISCLAIMER OF WARRANTY
                    726:
                    727: BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
                    728: FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
                    729: OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
                    730: PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
                    731: EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                    732: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
                    733: ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
                    734: YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
                    735: NECESSARY SERVICING, REPAIR, OR CORRECTION.
                    736:
                    737: IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
                    738: WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
                    739: REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
                    740: LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
                    741: OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
                    742: THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
                    743: RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
                    744: FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
                    745: SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
                    746: SUCH DAMAGES.

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