package List::Gather;
BEGIN {
  $List::Gather::AUTHORITY = 'cpan:FLORA';
}
{
  $List::Gather::VERSION = '0.06';
}
# ABSTRACT: Construct lists procedurally without temporary variables

use strict;
use warnings;
use Devel::CallParser;
use Devel::CallChecker;

use XSLoader;

XSLoader::load(
    __PACKAGE__,
    $List::Gather::{VERSION} ? ${ $List::Gather::{VERSION} } : (),
);

require B::Hooks::EndOfScope
    unless _QPARSE_DIRECTLY();

my @keywords;
BEGIN { @keywords = qw(gather take gathered) }

use Sub::Exporter -setup => {
    exports => [@keywords],
    groups  => { default => [@keywords] },
};


1;

__END__
=pod

=encoding utf-8

=head1 NAME

List::Gather - Construct lists procedurally without temporary variables

=head1 SYNOPSIS

  use List::Gather;

  my @list = gather {
      while (<$fh>) {
          next if /^\s*$/;
          next if /^\s*#/;
          last if /^(?:__END__|__DATA__)$/;
          take $_ if some_predicate($_);
      }

      take @defaults unless gathered;
  };

=head1 DESCRIPTION

This module provides a C<gather> keyword that allows lists to be constructed
procedurally, without the need for a temporary variable.

Within the block controlled by a C<gather> any call to C<take> pushes that
call's argument list to an implicitly created array.

C<gather> returns the list of values taken during its block's execution.

=head1 FUNCTIONS

=head2 gather

  gather { ... }
  gather({ ... })

Executes the block it has been provided with, collecting all arguments passed to
C<take> calls within it. After execution, the list of values collected is
returned.

Note that block C<gather> executes is equivalent to a C<do BLOCK>. It is neither
a code nor a loop. Loop control keywords, such as C<next> and C<last>, as well
as C<return> will behave accordingly.

Parens around the C<gather> block are optional.

=head2 take

  take LIST

Collects a C<LIST> of values within the C<gather> block it has been compiled in.

C<take> returns no meaningful value.

C<take> calls outside of the lexical scope of a C<gather> block are compile time
errors. Calling C<take> is only legal within the dynamic scope its associated
C<gather> block.

=head2 gathered

  gathered

Returns the list of items collected so far during the execution of a C<gather>
block.

C<gathered> calls outside of the lexical scope of a C<gather> block are compile
time errors. Calling C<gathered> outside of the dynamic scope of its associated
C<gather> block is legal.

=head1 EXAMPLES

  my @interesting_child_nodes = gather {
      for my $n (@nodes) {
          take $n->all_children
              if $n->is_interesting;
      }
  };

  my @last_10_events = gather {
      while ($log->has_event) {
          take $log->next_event;
      }

      shift gathered while gathered > 10;
  };

  my @search_results = gather {
      $user_interface->register_status_callback(sub {
          sprintf "Searching... Found %d matches so far", scalar gathered;
      });

      wait_for_search_results(sub {
          my ($result) = @_;
          take $result;
      }, @search_terms);

      $user_interface->register_status_callback(sub {
          sprintf "Found a total of %d", scalar gathered;
      });
  };

  my @leaf_nodes = gather {
      $graph->visit_all_nodes_recursively(sub {
          my ($node) = @_;
          take $node if $node->is_leaf;
      }
  };

=head1 SEE ALSO

=over 4

=item L<Syntax::Keyword::Gather>

A non-lexical gather/take implementation that's otherwise very similar to this one

=item L<Perl6::GatherTake>

An experimental implementation of a lazily evaluating gather/take

=item L<Perl6::Take>

A very simple gather/take implementation without lexical scoping

=item L<Perl6::Gather>

Like L<Syntax::Keyword::Gather>, but reliant on L<Perl6::Export>

=item L<List::Gen>

A comprehensive suit list generation functions featuring a non-lexical gather/take

=back

=head1 ACKNOWLEDGEMENTS

=over 4

=item *

Andrew Main (Zefram) E<lt>zefram@fysh.orgE<gt>

for providing his input in both the design and implementation of this module,
and writing much of the infrastructure that made this module possible in the
first place

=item *

Arthur Axel "fREW" Schmidt E<lt>frioux+cpan@gmail.comE<gt>

for his input on various aspects of this module as well as the many tests of his
L<Syntax::Keyword::Gather> module that this module shamelessly stole

=item *

Dave (autarch) Rolsky <autarch@urth.org> and Jesse (doy) Luehrs E<lt>doy@tozt.netE<gt>

for helping to improve both documentation and test coverage

=back

=head1 AUTHOR

Florian Ragwitz <rafl@debian.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2012 by Florian Ragwitz.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut

