1 package File
::KDBX
::Iterator
;
2 # ABSTRACT: KDBX database iterator
8 use File
::KDBX
::Util
qw(:class :load :search);
11 use Ref
::Util
qw(is_arrayref is_coderef is_ref is_scalarref);
14 BEGIN { mark_as_loaded
('Iterator::Simple::Iterator') }
15 extends
'Iterator::Simple::Iterator';
17 our $VERSION = '999.999'; # VERSION
21 \
&iterator
= File
::KDBX
::Iterator-
>new(\
&iterator
);
23 Blesses an iterator to augment it with buffering plus some useful utility methods
.
29 my $code = is_coderef
($_[0]) ? shift : sub { undef };
31 my $items = @_ == 1 && is_arrayref
($_[0]) ? $_[0] : \
@_;
32 return $class->SUPER::new
(sub {
34 if (@_ == 1 && is_arrayref
($_[0])) {
43 my $next = shift @$items;
44 return $next if defined $next;
52 $item = $iterator->next;
54 $item = $iterator->();
56 $item = $iterator->next(\
&query
);
57 $item = $iterator->next([\'simple expression
', @fields]);
59 Get the next item or C<undef> if there are no more items. If a query is passed, get the next matching item,
60 discarding any unmatching items before the matching item. Example:
62 my $item = $iterator->next(sub { $_->label =~ /Gym/ });
68 my $code = shift or return $self->();
70 $code = query_any($code, @_);
72 while (defined (local $_ = $self->())) {
73 return $_ if $code->($_);
80 $item = $iterator->peek;
82 Peek at the next item. Returns C<undef> if the iterator is empty. This allows you to access the next item
83 without draining it from the iterator. The same item will be returned the next time L</next> is called.
91 $self->($next) if defined $next;
97 $iterator->unget(\@items);
98 $iterator->unget(...);
100 $iterator->(\@items);
103 Replace the buffer or unshift one or more items to the current buffer.
110 my $self = shift; # Must shift in a statement before calling.
116 @items = $iterator->each;
118 $iterator->each(sub($item, $num, @args) { ... }, @args);
120 $iterator->each($method_name, ...);
122 Get or act on the rest of the items. There are three forms:
125 1. Without arguments, C<each> returns a list of the rest of the items.
126 2. Pass a coderef to be called once per item, in order. Arguments to the coderef are the item itself (also
127 C<$_>), its index number and then any extra arguments that were passed to C<each> after the coderef.
128 3. Pass a string that is the name of a method to be called on each object, in order. Any extra arguments
129 passed to C<each> after the method name are passed through to each method call. This form requires each
130 item be an object that C<can> the given method.
132 B<NOTE:> This method drains the iterator completely, leaving it empty. See L</CAVEATS>.
138 my $cb = shift or return @{$self->to_array};
140 if (is_coderef($cb)) {
142 $cb->($_, $count++, @_) while defined (local $_ = $self->());
144 elsif (!is_ref($cb)) {
145 $_->$cb(@_) while defined (local $_ = $self->());
154 \&iterator = $iterator->grep(\&query);
155 \&iterator = $iterator->grep([\'simple expression', @fields]);
157 Get a new iterator draining from an existing iterator but providing only items that pass a test
or are matched
162 sub where
{ shift-
>grep(@_) }
166 my $code = query_any
(@_);
168 ref($self)->new(sub {
169 while (defined (local $_ = $self->())) {
170 return $_ if $code->($_);
178 \
&iterator
= $iterator->map(\
&code
);
180 Get a new iterator draining from an existing iterator but providing modified items
.
188 ref($self)->new(sub {
189 local $_ = $self->();
190 return if !defined $_;
197 \
&iterator
= $iterator->sort_by($field, %options);
198 \
&iterator
= $iterator->sort_by(\
&get_value
, %options);
200 Get a new iterator draining from an existing iterator but providing items sorted by an object field
. Sorting
201 is done using L
<Unicode
::Collate
> (if available
) or C
<cmp> to
sort alphanumerically
. The C
<\
&get_value
>
202 subroutine
is called once
for each item
and should
return a string value
. Options
:
205 * C<ascending> - Order ascending if true, descending otherwise (default: true)
206 * C<case> - If true, take case into account, otherwise ignore case (default: true)
207 * C<collate> - If true, use B<Unicode::Collate> (if available), otherwise use perl built-ins (default: true)
208 * Any B<Unicode::Collate> option is also supported.
210 C<sort_by> and C<order_by> are aliases.
212 B<NOTE:> This method drains the iterator completely and places the sorted items onto the buffer. See
222 my $ascending = delete $args{ascending
} // !delete $args{descending
} // 1;
223 my $case = delete $args{case
} // !delete $args{no_case
} // 1;
224 my $collate = (delete $args{collate
} // !delete $args{no_collate
} // 1)
225 && try_load_optional
('Unicode::Collate');
227 if ($collate && !$case) {
229 # use a proper Unicode::Collate level to ignore case
232 $args{upper_before_lower
} //= 1;
235 $value = $case ? sub { $_[0]->$field // '' } : sub { uc($_[0]->$field) // '' } if !is_coderef
($value);
236 my @all = CORE
::map { [$_, $value->($_)] } @{$self->to_array};
239 my $c = Unicode
::Collate-
>new(%args);
241 @all = CORE
::map { $_->[0] } CORE
::sort { $c->cmp($a->[1], $b->[1]) } @all;
243 @all = CORE
::map { $_->[0] } CORE
::sort { $c->cmp($b->[1], $a->[1]) } @all;
247 @all = CORE
::map { $_->[0] } CORE
::sort { $a->[1] cmp $b->[1] } @all;
249 @all = CORE
::map { $_->[0] } CORE
::sort { $b->[1] cmp $a->[1] } @all;
259 Alias
for L
</order_by
>.
263 sub sort_by
{ shift-
>order_by(@_) }
267 \
&iterator
= $iterator->nsort_by($field, %options);
268 \
&iterator
= $iterator->nsort_by(\
&get_value
, %options);
270 Get a new iterator draining from an existing iterator but providing items sorted by an object field
. Sorting
271 is done numerically using C
<< <=> >>. The C
<\
&get_value
> subroutine
or C
<$field> accessor
is called once
for
272 each item
and should
return a numerical value
. Options
:
275 * C<ascending> - Order ascending if true, descending otherwise (default: true)
277 C<nsort_by> and C<norder_by> are aliases.
279 B<NOTE:> This method drains the iterator completely and places the sorted items onto the buffer. See
289 my $ascending = $args{ascending
} // !$args{descending
} // 1;
292 $value = sub { $_[0]->$field // 0 } if !is_coderef
($value);
293 my @all = CORE
::map { [$_, $value->($_)] } @{$self->to_array};
296 @all = CORE
::map { $_->[0] } CORE
::sort { $a->[1] <=> $b->[1] } @all;
298 @all = CORE
::map { $_->[0] } CORE
::sort { $b->[1] <=> $a->[1] } @all;
307 Alias
for L
</norder_by
>.
311 sub nsort_by
{ shift-
>norder_by(@_) }
315 \
&iterator
= $iterator->limit($count);
317 Get a new iterator draining from an existing iterator but providing only a limited number of items
.
319 C
<limit
> as an alias
for L
<Iterator
::Simple
/"$iterator->head($count)">.
323 sub limit
{ shift-
>head(@_) }
327 \
@array = $iterator->to_array;
329 Get the rest of the items from an iterator as an arrayref
.
331 B
<NOTE
:> This
method drains the iterator completely
, leaving it empty
. See L
</CAVEATS
>.
339 push @all, $_ while defined (local $_ = $self->());
345 $size = $iterator->count;
347 Count the rest of the items from an iterator
.
349 B
<NOTE
:> This
method drains the iterator completely but restores it to its pre-drained
state. See L
</CAVEATS
>.
356 my $items = $self->to_array;
358 return scalar @$items;
367 sub size
{ shift-
>count }
369 ##############################################################################
371 sub TO_JSON
{ $_[0]->to_array }
376 =for Pod::Coverage TO_JSON
380 my $kdbx = File::KDBX->load('database.kdbx', 'masterpw');
383 ->where(sub { $_->title =~ /bank/i })
392 A buffered iterator compatible with and expanding upon L<Iterator::Simple>, this provides an easy way to
393 navigate a L<File::KDBX> database. The documentation for B<Iterator::Simple> documents functions and methods
394 supported but this iterator that are not documented here, so consider that additional reading.
398 This iterator is buffered, meaning it can drain from an iterator subroutine under the hood, storing items
399 temporarily to be accessed later. This allows features like L</peek> and L</sort> which might be useful in the
400 context of KDBX databases which are normally pretty small so draining an iterator isn't cost-prohibitive.
402 The way this works is that if you call an iterator without arguments, it acts like a normal iterator. If you
403 call it with arguments, however, the arguments are added to the buffer. When called without arguments, the
404 buffer is drained before the iterator function is. Using L</unget> is equivalent to calling the iterator with
405 arguments, and as L</next> is equivalent to calling the iterator without arguments.
409 Some methods attempt to drain the iterator completely before returning. For obvious reasons, this won't work
410 for infinite iterators because your computer doesn't have infinite memory. This isn't a practical issue with
411 B<File::KDBX> lists which are always finite -- unless you do something weird like force a child group to be
412 its own ancestor -- but I'm noting it here as a potential issue if you use this iterator class for other
413 things (which you probably shouldn't do).