X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=lib%2FFile%2FKDBX%2FIterator.pm;h=89c0063f87c766f3eeb9a504b66745df972a3f89;hb=eefcd42a336641c8927b29d12c5c59443212468f;hp=f661706df50e262900af7590092b51336646ca82;hpb=e8e1363e4770ff29f5c2721318de9eb8fd7c8a22;p=chaz%2Fp5-File-KDBX diff --git a/lib/File/KDBX/Iterator.pm b/lib/File/KDBX/Iterator.pm index f661706..89c0063 100644 --- a/lib/File/KDBX/Iterator.pm +++ b/lib/File/KDBX/Iterator.pm @@ -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') } @@ -57,32 +57,17 @@ sub new { $item = $iterator->next([\'simple expression', @fields]); Get the next item or C 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->($_); @@ -130,11 +115,21 @@ sub unget { @items = $iterator->each; - $iterator->each(sub($item, $num) { ... }); + $iterator->each(sub($item, $num, @args) { ... }, @args); -Get the rest of the items. There are two forms: Without arguments, C 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<$_>. + $iterator->each($method_name, ...); + +Get or act on the rest of the items. There are three forms: + +=for :list +1. Without arguments, C 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 + C<$_>), its index number and then any extra arguments that were passed to C 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 after the method name are passed through to each method call. This form requires each + item be an object that C the given method. + +B This method drains the iterator completely, leaving it empty. See L. =cut @@ -142,23 +137,20 @@ 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]); @@ -167,11 +159,11 @@ by a 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->())) { @@ -200,23 +192,6 @@ sub map { }); } -=method filter - - \&iterator = $iterator->filter(\&query); - \&iterator = $iterator->filter([\'simple expression', @fields]); - -See L. - -=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); @@ -234,15 +209,11 @@ subroutine is called once for each item and should return a string value. Option C and C are aliases. -B 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 This method drains the iterator completely and places the sorted items onto the buffer. See +L. =cut -sub sort_by { shift->order_by(@_) } -sub nsort_by { shift->norder_by(@_) } - sub order_by { my $self = shift; my $field = shift; @@ -283,7 +254,13 @@ sub order_by { return $self; } -=method nsort_by +=method sort_by + +Alias for L. + +=cut + +sub sort_by { shift->order_by(@_) } =method norder_by @@ -291,17 +268,16 @@ 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 - Order ascending if true, descending otherwise (default: true) C and C are aliases. -B 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 This method drains the iterator completely and places the sorted items onto the buffer. See +L. =cut @@ -326,14 +302,33 @@ sub norder_by { return $self; } +=method nsort_by + +Alias for L. + +=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 as an alias for Lhead($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 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 This method drains the iterator completely, leaving it empty. See L. =cut @@ -347,19 +342,15 @@ sub to_array { =method count -=method size - $size = $iterator->count; Count the rest of the items from an iterator. -B 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 This method drains the iterator completely but restores it to its pre-drained state. See L. =cut -sub size { +sub count { my $self = shift; my $items = $self->to_array; @@ -367,7 +358,15 @@ sub size { return scalar @$items; } -sub count { shift->size } +=method size + +Alias for L. + +=cut + +sub size { shift->count } + +############################################################################## sub TO_JSON { $_[0]->to_array } @@ -378,9 +377,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,7 +390,8 @@ __END__ =head1 DESCRIPTION A buffered iterator compatible with and expanding upon L, this provides an easy way to -navigate a L database. +navigate a L database. The documentation for B documents functions and methods +supported but this iterator that are not documented here, so consider that additional reading. =head2 Buffer @@ -402,4 +404,12 @@ call it with arguments, however, the arguments are added to the buffer. When cal buffer is drained before the iterator function is. Using L is equivalent to calling the iterator with arguments, and as L 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 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). + =cut