Array-Extract

 view release on metacpan or  search on metacpan

lib/Array/Extract/Example.pod  view on Meta::CPAN

=head1 NAME

Array::Extract::Example - Documenting an example use of Array::Extract

=head1 DESCRIPTION

While I normally use OmniFocus as a GTD tool to manage my todo lists,
sometimes I want to collaborate on a todo list with someone else and
I don't want them to have to use a complicated and expensive tool.
I've often found in this situation a simple shared text file is the way
to go.  A file on the office fileserver, or in a shared Dropbox folder,
in a obvious format that any can understand with a glance.

Here's what one looks like:

  [X] (extract) Complete coding
  [X] (extract) Get Zefram to code review my code
  [X] (yapc) Write talk submission for YAPC::NA
  [X] (yapc) submit talk proposal with ACT
  [ ] (extract) Write Array::Extract::Example document
  [ ] (extract) Check in and push to github
  [ ] (extract) Upload to CPAN
  [ ] (extract) Publish a blog post about it

In the above example two tasks each from the the C<extract> project and the
C<yapc> project have been marked as completed.  Periodically I want to move
these "done" items to a separate archive list - the done file - so they don't
clutter up my list.  That's something I'm going to want to automate with Perl.

The way I've chosen to write that script is to use  Tie::File, where each
element of the array corresponds to a line of the file.

=head2 Alternatives to Grepping

At first glance removing all the lines from our array that are ticked might
seem like a simple use of grep:

  tie my @todo, "Tie::File", $filename or die $!;
  @todo = grep { !/\A\[[^ ]]/ } @todo;

But that's throwing away everything that we want to move to the done file. An
alternative might be to write a grep with side effects:

  tie my @todo, "Tie::File", $filename or die $!;
  open my $done_fh, ">>", $done_filename or die $!;
  @todo = grep {
    !/\A\[[^ ]]/ || do {
      say { $done_fh } $_;
    0 } 
  } @todo;

But that's ugly.  The code gets much uglier still if you want a banner
preceding the first new entry into the done file saying when the actions were
moved there.

What I ended up doing was writing a new module called Array::Extract which
exports a function C<extract> that does exactly what you might expect:

  my @done = extract { /\A\[[^ ]]/ } @todo;

C<@todo> is modified to remove anything that the block returns true for and
those elements are placed in C<@done>.

  open my $done_fh, ">>", $done_filename or die $!;
  my @done = extract { /\A\[[^ ]]/ } @todo;
  print { $done_fh } map { "$_\n" }
    "","Items archived @{[ DateTime->now ]}:","",@done;

=head2 Needs more actions

Of course, if all I wanted to do was remove the actions that had been
completed I probably wouldn't have reached for Tie::File, but for my next
trick I'm going to need to insert some extra content at the top of the file
once I'm done processing it.



( run in 0.644 second using v1.01-cache-2.11-cpan-39bf76dae61 )