File-Kvpar

 view release on metacpan or  search on metacpan

lib/File/Kvpar.pm  view on Meta::CPAN

    my ($fh, $elems, $pos) = @$self{qw(fh elements pos)};
    seek $fh, 0, 2 or die "Can't seek to end: $!";
    my @elems = @$elems;
    push @elems, @_;
    my @pars = map { _hash2par($_) } @_;
    print $fh @pars;
    $self->{'pos'} = @$elems;
    @$elems = @elems;
    return $self;
}

sub truncate {
    my ($self) = @_;
    my ($fh, $elems, $pos) = @$self{qw(fh elements pos)};
    my $ofs = tell $fh;
    truncate $fh, $ofs;
    splice @$elems, $pos;
    return $self;
}

sub _hash2par {
    my ($hash) = @_;
    my $par = '';
    my %hash = %$hash;
    my ($at, $lb) = delete @hash{'@','#'};
    if (defined $at) {
        $par .= '@' . $at;
        $par .= ' ' . $lb if defined $lb;
        $par .= "\n";
    }
    foreach my $k (sort keys %hash) {
        my $v = $hash{$k};
        $par .= "$k $v\n" if defined $v;
    }
    $par = "#empty\n" if !length $par;
    return $par . "\n";
}

sub _par2hash {
    my ($par) = @_;
    chomp $par;
    my %hash;
    foreach (split /\n/, $par) {
        if (/^[@](\S*)(?: (.+))?$/) {
            $hash{'@'} = $1 if length $1;
            $hash{'#'} = $2 if defined $2;
        }
        elsif (/^[#]/) {
            next;
        }
        elsif (/^(\S+) (.*)$/) {
            $hash{$1} = $2;
        }
    }
    return \%hash;
}

sub _read_one {
    my ($self) = @_;
    my $fh = $self->{'fh'};
    local $/ = '';
    my $elems = $self->{'elements'};
    if (my $par = <$fh>) {
        $self->{'pos'}++;
        my $hash = _par2hash($par);
        push @{ $elems }, $hash;
        $self->{'have_read'} |= HEAD;
        return $hash;
    }
    else {
        $self->{'have_read'} |= TAIL;
        return;
    }
}

sub _read_remainder {
    my ($self) = @_;
    my ($hash, @rem);
    while ($hash = $self->_read_one) {
        push @rem, $hash;
    }
    return @rem;
}

sub head {
    my ($self) = @_;
    my $elems = $self->{'elements'};
    return $self->_read_one if !@$elems;
    return $elems->[0];
}

sub tail {
    my ($self) = @_;
    my $elems = $self->{'elements'};
    $self->_read_remainder if !( $self->{'have_read'} & TAIL );
    return if @$elems < 2;
    return @$elems[1..$#$elems];
}

sub reset {
    my ($self) = @_;
    seek $self->{'fh'}, 0, 0 or die "Can't seek to beginning of file: $!";
    $self->{'pos'} = 0;
    $self->{'elements'} = [];
    $self->{'have_read'} = 0;
    return $self;
}

sub elements {
    my ($self) = @_;
    my $elems = $self->{'elements'};
    $self->_read_remainder if ( $self->{'have_read'} & (HEAD|TAIL) ) != (HEAD|TAIL);
    return @$elems;
}

1;

=pod

=head1 NAME



( run in 1.392 second using v1.01-cache-2.11-cpan-8dfa8b56332 )