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

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

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