App-CSV
view release on metacpan or search on metacpan
lib/App/CSV.pm view on Meta::CPAN
BEGIN {
# One day, MooseX::Getopt will allow us to pass pass_through to Getopt::Long.
# Until then, do the following ugly thing unconditionally.
# (We don't need a BEGIN block here yet. But we will once we start fussing
# around with version numbers.)
use Getopt::Long qw(:config pass_through);
}
with 'MooseX::Getopt';
# Create "hasrw" and "hasro" sugar for less cumbersome attribute declarations.
# Why isn't this in Moose?
BEGIN {
my $mk_has = sub {
my($access) = @_;
return sub {
my($attr, @args) = @_;
has $attr => (
is => $access,
metaclass => 'Getopt', # For cmd_aliases
@args,
);
};
};
no strict 'refs';
*hasrw = $mk_has->('rw');
*hasro = $mk_has->('ro');
}
# Input and output filenames. Significant when we want to DWIM with TSV files.
hasrw input => (isa => 'Str', cmd_aliases => 'i');
hasrw output => (isa => 'Str', cmd_aliases => 'o');
# isa => 'FileHandle' (or IO::String...)
hasrw _input_fh => ();
hasrw _output_fh => ();
# TODO: command line aliases?
hasro from_tsv =>
(isa => 'Bool', cmd_aliases => 'from-tsv', predicate => 'has_from_tsv');
hasro to_tsv =>
(isa => 'Bool', cmd_aliases => 'to-tsv', predicate => 'has_to_tsv');
hasrw _init => (isa => 'Bool');
# Normalized column indexes.
hasrw columns => (isa => 'ArrayRef[Int]', cmd_aliases => 'c');
# Named fields.
hasrw fields => (isa => 'ArrayRef[Str]', cmd_aliases => 'f');
# The input and output CSV processors.
hasrw _input_csv => ();
hasrw _output_csv => ();
# Text::CSV options, straight from the manpage.
# We override Text::CSV's default here... because it's WRONG.
our %TextCSVOptions = (
# name => [type, default, alias, @extra_opts]
quote_char => ['Str', '"', 'q'],
escape_char => ['Str', '"', 'e'],
sep_char => ['Str', ',', 's', is => 'rw'],
eol => ['Any', ''],
always_quote => ['Int', 0],
binary => ['Int', 1, 'b'],
keep_meta_info => ['Int', 0, 'k'],
allow_loose_quotes => ['Int', 0],
allow_loose_escapes => ['Int', 0],
allow_whitespace => ['Int', 0, 'w'],
verbatim => ['Int', 0],
);
# output CSV processor options default to whatever the input option is.
# But you can override it just for output by saying --output_foo instead
# of --foo. (Thanks, gphat and t0m.)
while (my($attr, $opts) = each %TextCSVOptions) {
my($type, $default, $short, @extra_opts) = @$opts;
hasro $attr => (
isa => $type,
default => $default,
__aliases($attr, $short),
@extra_opts
);
hasro "output_$attr" => (
isa => $type,
lazy => 1,
default => sub { $_[0]->$attr },
__output_aliases($attr),
@extra_opts,
);
}
sub __aliases {
my($attr, $short) = @_;
my @aliases;
(my $dashes = $attr) =~ s/_/-/g;
push @aliases, $dashes if $attr ne $dashes;
push @aliases, $short if $short;
return @aliases ? (cmd_aliases => \@aliases) : ();
}
sub __output_aliases {
return __aliases("output_" . shift);
}
sub __normalize_column {
my($in) = @_;
return ($in <= 0) ? $in : $in - 1;
}
sub _get_header_map {
my ($self) = @_;
my $header_line = $self->_peek_line;
my %header_map;
my $field_number = 0;
for my $field (@$header_line) {
$header_map{$field} = ++$field_number;
}
return \%header_map;
}
sub _fields_to_columns {
my ($self, $fields) = @_;
my @all_fields = map { /^(\d+)-(\d+)$/ ? $1 .. $2 : $_ } map { split "," } @$fields;
my @named_fields = grep { /\D/ } @all_fields;
( run in 1.815 second using v1.01-cache-2.11-cpan-39bf76dae61 )