DBIx-DR

 view release on metacpan or  search on metacpan

lib/DBIx/DR/Iterator.pm  view on Meta::CPAN

use utf8;
use strict;
use warnings;

package DBIx::DR::Iterator;
use Scalar::Util qw(blessed weaken);
use DBIx::DR::Util;
use Carp;


# Perl 5.18 refuses smartmatch
my $is = sub($$) {
    my ($v1, $v2) = @_;
    return 0 if defined($v1) xor defined($v2);
    return 1 unless defined $v1;
    return $v1 eq $v2;
};


sub new {
    my ($class, $fetch, %opts) = @_;

    my ($is_hash, $is_array) = (0, 0);

    my $count;

    if ('ARRAY' eq ref $fetch) {
        $is_array = 1;
        if ($count = @$fetch) {
            croak 'You must use array of hashrefs'
                unless 'HASH' eq ref $fetch->[0] or blessed $fetch->[0];
        }
    } elsif ('HASH' eq ref $fetch) {
        $is_hash = 1;
        my ($k) = each %$fetch;
        if ($count = keys %$fetch) {
            croak 'You must use hash of hashrefs'
                unless 'HASH' eq ref $fetch->{$k} or blessed $fetch->{$k};
        }
    } else {
        croak "You should bless 'HASHREF' or 'ARRAYREF' value";
    }


    my ($item_class, $item_constructor) =
        camelize($opts{'-item'} || 'dbix-dr-iterator-item#new');

    my $keep_blessed = $opts{-keep_blessed};
    $keep_blessed //= 1;


    return bless {
        fetch               => $fetch,
        is_hash             => $is_hash,
        is_array            => $is_array,
        count               => $count,
        iterator            => 0,
        item_class          => $item_class,
        item_constructor    => $item_constructor,
        is_changed          => 0,
        keep_blessed        => $keep_blessed,
        noitem_iter         => $opts{-noitem_iter} ? 1 : 0,
    } => ref($class) || $class;
}


lib/DBIx/DR/Iterator.pm  view on Meta::CPAN

    $item;
}


sub find : method {
    my ($self, $field, $value) = @_;

    $self->reset;
    while(my $item = $self->next) {
        return $item if $is->($item->$field, $value);
    }
    return;
}



package DBIx::DR::Iterator::Item;
use Scalar::Util ();
use Carp ();

# to exclude this method from AUTOLOAD
sub DESTROY {}

sub AUTOLOAD {
    our $AUTOLOAD;
    my ($method) = $AUTOLOAD =~ /.*::(.*)/;
    my ($self, $value) = @_;

    Carp::croak "Can't find method '$self->$method'" unless ref $self;
    Carp::croak "Can't find method '$method' in this item"
        unless exists $self->{$method};

    if (@_ > 1) {
        my $is_changed;

        if (ref $value and ref $self->{$method}) {
            $is_changed = Scalar::Util::refaddr($value)
                != Scalar::Util::refaddr($self->{$method});
        } elsif(ref($value) ne ref($self->{$method})) {
            $is_changed = 1;
        } elsif(defined $value and defined $self->{$method}) {
            $is_changed = $value ne $self->{$method};
        } elsif(defined $value xor defined $self->{$method}) {
            $is_changed = 1;
        }

        $self->is_changed(1) if $is_changed;
        $self->{$method} = $value;
    }

    return $self->{$method};
}

sub new {
    my ($class, $object, $iterator) = @_;
    return unless defined $object;
    Carp::croak "Usage: DBIx::DR::Iterator::Item->new(HASHREF [, iterator ])"
        unless 'HASH' eq ref $object;
    my $self = bless $object => ref($class) || $class;
    $self->{iterator} = $iterator;
    Scalar::Util::weaken($self->{iterator});
    $self->{is_changed} = 0;
    return $self;
}

sub is_changed {
    my ($self, $value) = @_;
    if (@_ > 1) {{
        $self->{is_changed} = $value ? 1 : 0;

        last unless $self->{is_changed};
        last unless Scalar::Util::blessed $self->{iterator};
        last unless $self->{iterator}->can('is_changed');
        $self->{iterator}->is_changed( 1 );
    }}
    return $self->{is_changed};
}

sub can {
    my ($self, $method) = @_;
    return 1 if ref $self and exists $self->{$method};
    return $self->SUPER::can($method);
}


1;

=head1 NAME

DBIx::DR::Iterator - iterator for L<DBIx::DR>.

=head1 SYNOPSIS

    my $it = DBIx::DR::Iterator->new($arrayref);

    printf "Rows count: %d\n", $it->count;

    while(my $row == $it->next) {
        print "Row: %s\n", $row->field;
    }

    my $row = $it->get(15); # element 15



    my $it = DBIx::DR::Iterator->new($hashref);

    printf "Rows count: %d\n", $it->count;

    while(my $row == $it->next) {
        print "Row: %s\n", $row->field;
    }

    my $row = $it->get('abc'); # element with key name eq 'abc'


=head1 DESCRIPTION

The package constructs iterator from HASHREF or ARRAYREF value.

=head1 Methods

lib/DBIx/DR/Iterator.pm  view on Meta::CPAN

=head2 get(name|number)

Returns element by 'B<name|number>'. It will throw exception if element
isn't L<exists|exists(name|number)>.

=head2 next

Returns next element or B<undef>.

=head2 reset

Resets internal iterator (that is used by L<next>).

=head2 all

Returns all elements (as an array).

If You notice an argument it will extract specified fields:

    my @ids = $it->all('id');

The same as:

    my @ids = map { $_->id } $it->all;

=head2 grep

Constructs new iterator that is subset of parent iterator.

    my $busy = $list->grep(sub { $_[0]->busy ? 1 : 0 });

=head2 push

Pushes one element into iterator.

If You use HASH-iterator You have to note key name.

=head3 Example

    $hiter->push(abc => { id => 1 });
    $hiter->push(abc => $oiter->get('abc'));

    $aiter->push({ id => 1 });

=head1 DBIx::DR::Iterator::Item

One row. It has methods names coincident with field names. Also it has a few
additional methods:

=head2 new

Constructor. Receives two arguments: B<HASHREF> and link to
L<iterator|DBIx::DR::Iterator>.

    my $row = DBIx::DR::Iterator::Item->new({ id => 1 });
    $row = DBIx::DR::Iterator::Item->new({ id => 1 }, $iterator); }

=head2 iterator

Returns (or set) iterator object. The link is created by constructor.
This is a L<weaken|Scalar::Util/weaken> link.

=head2 is_changed

Returns (or set) flag if the row has been changed. If You change any of
row's fields the flag will be set. Also iterator's flag will be set.


=head1 COPYRIGHT

 Copyright (C) 2011 Dmitry E. Oboukhov <unera@debian.org>
 Copyright (C) 2011 Roman V. Nikolaev <rshadow@rambler.ru>

 This program is free software, you can redistribute it and/or
 modify it under the terms of the Artistic License.

=cut



( run in 0.931 second using v1.01-cache-2.11-cpan-7f9471e7e0a )