package Text::LTSV;
use strict;
use warnings;
our $VERSION = '0.03';
use IO::File;
use Carp qw/croak/;
sub new {
my ($self, @kv) = @_;
# bless \@kv, $self;
return bless {
_kv => \@kv,
_wants => [],
_ignores => [],
}, $self;
}
sub ignore_fields {
my ($self, @keys) = @_;
@keys ? $self->{_ignores} = \@keys : return $self->{_ignores};
}
sub want_fields {
my ($self, @keys) = @_;
@keys ? $self->{_wants} = \@keys : return $self->{_wants};
}
sub ordered {
my $self = shift;
@_ ? $self->{_ordered} = shift : return $self->{_ordered};
}
sub has_wants {
@{shift->want_fields} ? 1 : 0;
}
sub has_ignores {
@{shift->ignore_fields} ? 1 : 0;
}
sub parse_line {
my ($self, $line) = @_;
chomp $line;
my $has_wants = $self->has_wants;
my $has_ignores = $self->has_ignores;
my %wants;
if ($has_wants) {
%wants = map { $_ => 1 } @{$self->want_fields};
}
my %ignores;
if ($has_ignores) {
%ignores = map { $_ => 1 } @{$self->ignore_fields};
}
my %kv;
if ($self->ordered) {
require Tie::IxHash;
tie %kv, 'Tie::IxHash';
}
for (map { [ split ':', $_, 2 ] } split "\t", $line) {
next if $has_ignores and $ignores{$_->[0]};
next if $has_wants and not $wants{$_->[0]};
$kv{$_->[0]} = $_->[1];
}
return \%kv;
}
sub parse_file {
my ($self, $path, $opt) = @_;
$opt ||= {};
my $fh = IO::File->new($path, $opt->{utf8} ? '<:utf8' : 'r') or croak $!;
my @out;
while (my $line = $fh->getline) {
push @out, $self->parse_line($line);
}
$fh->close;
return \@out;
}
sub parse_file_utf8 {
my ($self, $path) = @_;
return $self->parse_file($path, { utf8 => 1 });
}
sub to_s {
my $self = shift;
my $n = @{$self->{_kv}};
my @out;
for (my $i = 0; $i < $n; $i += 2) {
push @out, join ':', $self->{_kv}->[$i], $self->{_kv}->[$i+1];
}
return join "\t", @out;
}
1;
__END__
=head1 NAME
Text::LTSV - Labeled Tab Separeted Value manipulator
=head1 SYNOPSIS
use Text::LTSV;
my $p = Text::LTSV->new;
my $hash = $p->parse_line("hoge:foo\tbar:baz\n");
is $hash->{hoge}, 'foo';
is $hash->{bar}, 'baz';
my $data = $p->parse_file('./t/test.ltsv'); # or parse_file_utf8
is $data->[0]->{hoge}, 'foo';
is $data->[0]->{bar}, 'baz';
# Only want certain fields?
my $p = Text::LTSV->new;
$p->want_fields('hoge');
$p->parse_line("hoge:foo\tbar:baz\n");
my $ltsv = Text::LTSV->new(
hoge => 'foo',
bar => 'baz',
);
is $ltsv->to_s, "hoge:foo\tbar:baz";
=head1 DESCRIPTION
Labeled Tab Separated Value L<http://stanaka.hatenablog.com/entry/2013/02/05/214833> is a Key-Value pair + line-based text format for log files, especially HTTP access_log.
This module provides a simple way to process LSTV-based string and files, which converts Key-Value pair(s) of LSTV to Perl's hash reference(s).
=head1 AUTHOR
Naoya Ito E<lt>i.naoya@gmail.comE<gt>
=head1 LICENSE
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut