]> Dogcows Code - chaz/p5-File-KDBX/blobdiff - lib/File/KDBX/Iterator.pm
Fix documentation typos
[chaz/p5-File-KDBX] / lib / File / KDBX / Iterator.pm
index f661706df50e262900af7590092b51336646ca82..bf7b4eb060a284a634d121cfa017856cc0948e75 100644 (file)
@@ -1,5 +1,5 @@
 package File::KDBX::Iterator;
-# PACKAGE: KDBX database iterator
+# ABSTRACT: KDBX database iterator
 
 use warnings;
 use strict;
@@ -8,7 +8,7 @@ use File::KDBX::Error;
 use File::KDBX::Util qw(:class :load :search);
 use Iterator::Simple;
 use Module::Loaded;
-use Ref::Util qw(is_arrayref is_coderef is_scalarref);
+use Ref::Util qw(is_arrayref is_coderef is_ref is_scalarref);
 use namespace::clean;
 
 BEGIN { mark_as_loaded('Iterator::Simple::Iterator') }
@@ -20,7 +20,7 @@ our $VERSION = '999.999'; # VERSION
 
     \&iterator = File::KDBX::Iterator->new(\&iterator);
 
-Blesses an iterator to augment it with buffering plus some useful utility methods.
+Bless an iterator to augment it with buffering plus some useful utility methods.
 
 =cut
 
@@ -54,35 +54,19 @@ sub new {
     $item = $iterator->();
 
     $item = $iterator->next(\&query);
-    $item = $iterator->next([\'simple expression', @fields]);
 
 Get the next item or C<undef> if there are no more items. If a query is passed, get the next matching item,
-discarding any items before the matching item that do not match. Example:
+discarding any unmatching items before the matching item. Example:
 
     my $item = $iterator->next(sub { $_->label =~ /Gym/ });
 
 =cut
 
-sub _create_query {
-    my $self = shift;
-    my $code = shift;
-
-    if (is_coderef($code) || overload::Method($code, '&{}')) {
-        return $code;
-    }
-    elsif (is_scalarref($code)) {
-        return simple_expression_query($$code, @_);
-    }
-    else {
-        return query($code, @_);
-    }
-}
-
 sub next {
     my $self = shift;
     my $code = shift or return $self->();
 
-    $code = $self->_create_query($code, @_);
+    $code = query_any($code, @_);
 
     while (defined (local $_ = $self->())) {
         return $_ if $code->($_);
@@ -109,13 +93,17 @@ sub peek {
 
 =method unget
 
+    # Replace buffer:
     $iterator->unget(\@items);
-    $iterator->unget(...);
     # OR equivalently
     $iterator->(\@items);
-    $iterator->(...);
 
-Replace the buffer or unshift one or more items to the current buffer.
+    # Unshift onto buffer:
+    $iterator->unget(@items);
+    # OR equivalently
+    $iterator->(@items);
+
+Replace the buffer (first form) or unshift one or more items to the current buffer (second form).
 
 See L</Buffer>.
 
@@ -130,11 +118,22 @@ sub unget {
 
     @items = $iterator->each;
 
-    $iterator->each(sub($item, $num) { ... });
+    $iterator->each(sub($item, $num, @args) { ... }, @args);
+
+    $iterator->each($method_name, ...);
 
-Get the rest of the items. There are two forms: Without arguments, C<each> returns a list of the rest of the
-items. Or pass a coderef to be called once per item, in order. The item is passed as the first argument to the
-given subroutine and is also available as C<$_>.
+Get or act on the rest of the items. This method has three forms:
+
+=for :list
+1. Without arguments, C<each> returns a list of the rest of the items.
+2. Pass a coderef to be called once per item, in order. Arguments to the coderef are the item itself (also
+   available as C<$_>), its index number and then any extra arguments that were passed to C<each> after the
+   coderef.
+3. Pass a string that is the name of a method to be called on each object, in order. Any extra arguments
+   passed to C<each> after the method name are passed through to each method call. This form requires each
+   item be an object that C<can> the given method.
+
+B<NOTE:> This method drains the iterator completely, leaving it empty. See L</CAVEATS>.
 
 =cut
 
@@ -142,36 +141,36 @@ sub each {
     my $self = shift;
     my $cb = shift or return @{$self->to_array};
 
-    my $count = 0;
-    $cb->($_, $count++) while defined (local $_ = $self->());
+    if (is_coderef($cb)) {
+        my $count = 0;
+        $cb->($_, $count++, @_) while defined (local $_ = $self->());
+    }
+    elsif (!is_ref($cb)) {
+        $_->$cb(@_) while defined (local $_ = $self->());
+    }
     return $self;
 }
 
-=method limit
-
-    \&iterator = $iterator->limit($count);
-
-Get a new iterator draining from an existing iterator but providing only a limited number of items.
-
-=cut
-
-sub limit { shift->head(@_) }
-
 =method grep
 
+=method where
+
     \&iterator = $iterator->grep(\&query);
-    \&iterator = $iterator->grep([\'simple expression', @fields]);
+    \&iterator = $iterator->grep(sub($item) { ... });
 
 Get a new iterator draining from an existing iterator but providing only items that pass a test or are matched
-by a query.
+by a query. In its basic form this method is very much like perl's built-in grep function, except for
+iterators.
+
+There are many examples of the various forms of this method at L<File::KDBX/QUERY>.
 
 =cut
 
+sub where { shift->grep(@_) }
+
 sub grep {
     my $self = shift;
-    my $code = shift;
-
-    $code = $self->_create_query($code, @_);
+    my $code = query_any(@_);
 
     ref($self)->new(sub {
         while (defined (local $_ = $self->())) {
@@ -185,7 +184,8 @@ sub grep {
 
     \&iterator = $iterator->map(\&code);
 
-Get a new iterator draining from an existing iterator but providing modified items.
+Get a new iterator draining from an existing iterator but providing modified items. In its basic form this
+method is very much like perl's built-in map function, except for iterators.
 
 =cut
 
@@ -200,23 +200,6 @@ sub map {
     });
 }
 
-=method filter
-
-    \&iterator = $iterator->filter(\&query);
-    \&iterator = $iterator->filter([\'simple expression', @fields]);
-
-See L<Iterator::Simple/"ifilter $iterable, sub{ CODE }">.
-
-=cut
-
-sub filter {
-    my $self = shift;
-    my $code = shift;
-    return $self->SUPER::filter($self->_create_query($code, @_));
-}
-
-=method sort_by
-
 =method order_by
 
     \&iterator = $iterator->sort_by($field, %options);
@@ -232,17 +215,11 @@ subroutine is called once for each item and should return a string value. Option
 * C<collate> - If true, use B<Unicode::Collate> (if available), otherwise use perl built-ins (default: true)
 * Any B<Unicode::Collate> option is also supported.
 
-C<sort_by> and C<order_by> are aliases.
-
-B<NOTE:> This method drains the iterator completely but adds items back onto the buffer, so the iterator is
-still usable afterward. Nevertheless, you mustn't call this on an infinite iterator or it will run until
-available memory is depleted.
+B<NOTE:> This method drains the iterator completely and places the sorted items onto the buffer. See
+L</CAVEATS>.
 
 =cut
 
-sub sort_by  { shift->order_by(@_)  }
-sub nsort_by { shift->norder_by(@_) }
-
 sub order_by {
     my $self    = shift;
     my $field   = shift;
@@ -283,7 +260,13 @@ sub order_by {
     return $self;
 }
 
-=method nsort_by
+=method sort_by
+
+Alias for L</order_by>.
+
+=cut
+
+sub sort_by { shift->order_by(@_)  }
 
 =method norder_by
 
@@ -291,17 +274,14 @@ sub order_by {
     \&iterator = $iterator->nsort_by(\&get_value, %options);
 
 Get a new iterator draining from an existing iterator but providing items sorted by an object field. Sorting
-is done numerically using C<< <=> >>. The C<\&get_value> subroutine is called once for each item and should
-return a numerical value. Options:
+is done numerically using C<< <=> >>. The C<\&get_value> subroutine or C<$field> accessor is called once for
+each item and should return a numerical value. Options:
 
 =for :list
 * C<ascending> - Order ascending if true, descending otherwise (default: true)
 
-C<nsort_by> and C<norder_by> are aliases.
-
-B<NOTE:> This method drains the iterator completely but adds items back onto the buffer, so the iterator is
-still usable afterward. Nevertheless, you mustn't call this on an infinite iterator or it will run until
-available memory is depleted.
+B<NOTE:> This method drains the iterator completely and places the sorted items onto the buffer. See
+L</CAVEATS>.
 
 =cut
 
@@ -326,14 +306,33 @@ sub norder_by {
     return $self;
 }
 
+=method nsort_by
+
+Alias for L</norder_by>.
+
+=cut
+
+sub nsort_by { shift->norder_by(@_) }
+
+=method limit
+
+    \&iterator = $iterator->limit($count);
+
+Get a new iterator draining from an existing iterator but providing only a limited number of items.
+
+C<limit> is an alias for L<< Iterator::Simple/"$iterator->head($count)" >>.
+
+=cut
+
+sub limit { shift->head(@_) }
+
 =method to_array
 
     \@array = $iterator->to_array;
 
 Get the rest of the items from an iterator as an arrayref.
 
-B<NOTE:> This method drains the iterator completely, leaving the iterator empty. You mustn't call this on an
-infinite iterator or it will run until available memory is depleted.
+B<NOTE:> This method drains the iterator completely, leaving it empty. See L</CAVEATS>.
 
 =cut
 
@@ -347,19 +346,15 @@ sub to_array {
 
 =method count
 
-=method size
-
     $size = $iterator->count;
 
 Count the rest of the items from an iterator.
 
-B<NOTE:> This method drains the iterator completely but adds items back onto the buffer, so the iterator is
-still usable afterward. Nevertheless, you mustn't call this on an infinite iterator or it will run until
-available memory is depleted.
+B<NOTE:> This method drains the iterator completely but restores it to its pre-drained state. See L</CAVEATS>.
 
 =cut
 
-sub size {
+sub count {
     my $self = shift;
 
     my $items = $self->to_array;
@@ -367,7 +362,15 @@ sub size {
     return scalar @$items;
 }
 
-sub count { shift->size }
+=method size
+
+Alias for L</count>.
+
+=cut
+
+sub size { shift->count }
+
+##############################################################################
 
 sub TO_JSON { $_[0]->to_array }
 
@@ -378,9 +381,11 @@ __END__
 
 =head1 SYNOPSIS
 
+    my $kdbx = File::KDBX->load('database.kdbx', 'masterpw');
+
     $kdbx->entries
-        ->grep(sub { $_->title =~ /bank/i })
-        ->sort_by('title')
+        ->where(sub { $_->title =~ /bank/i })
+        ->order_by('title')
         ->limit(5)
         ->each(sub {
             say $_->title;
@@ -389,17 +394,30 @@ __END__
 =head1 DESCRIPTION
 
 A buffered iterator compatible with and expanding upon L<Iterator::Simple>, this provides an easy way to
-navigate a L<File::KDBX> database.
+navigate a L<File::KDBX> database. The documentation for B<Iterator::Simple> documents functions and methods
+supported by this iterator that are not documented here, so consider that additional reading.
 
 =head2 Buffer
 
 This iterator is buffered, meaning it can drain from an iterator subroutine under the hood, storing items
-temporarily to be accessed later. This allows features like L</peek> and L</sort> which might be useful in the
-context of KDBX databases which are normally pretty small so draining an iterator isn't cost-prohibitive.
+temporarily to be accessed later. This allows features like L</peek> and L</order_by> which might be useful in
+the context of KDBX databases which are normally pretty small so draining an iterator completely isn't
+cost-prohibitive in terms of memory usage.
 
 The way this works is that if you call an iterator without arguments, it acts like a normal iterator. If you
 call it with arguments, however, the arguments are added to the buffer. When called without arguments, the
 buffer is drained before the iterator function is. Using L</unget> is equivalent to calling the iterator with
-arguments, and as L</next> is equivalent to calling the iterator without arguments.
+arguments, and L</next> is equivalent to calling the iterator without arguments.
+
+=head1 CAVEATS
+
+Some methods attempt to drain the iterator completely before returning. For obvious reasons, this won't work
+for infinite iterators because your computer doesn't have infinite memory. This isn't a practical issue with
+B<File::KDBX> lists which are always finite -- unless you do something weird like force a child group to be
+its own ancestor -- but I'm noting it here as a potential issue if you use this iterator class for other
+things (which you probably shouldn't do).
+
+KDBX databases are always fully-loaded into memory anyway, so there's not a significant memory cost to
+draining an iterator completely.
 
 =cut
This page took 0.0334 seconds and 4 git commands to generate.