Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce a new fix map to move several fields by a lookup table #366

Merged
merged 6 commits into from
Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/Catmandu/Fix/lookup.pm
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,6 @@ looking up its value in a dictionary

=head1 SEE ALSO

L<Catmandu::Fix>
L<Catmandu::Fix>, L<Catmandu::Fix::map>

=cut
97 changes: 97 additions & 0 deletions lib/Catmandu/Fix/map.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package Catmandu::Fix::map;

use Catmandu::Sane;

use Catmandu::Importer::CSV;
use Catmandu::Util::Path qw(as_path);
use Catmandu::Util qw(is_value);
use Clone qw(clone);
use Moo;
use namespace::clean;
use Catmandu::Fix::Has;
use Data::Dumper;

with 'Catmandu::Fix::Builder';

has file => (fix_arg => 1);
has csv_args => (fix_opt => 'collect');
has dictionary => (is => 'lazy', init_arg => undef);

sub _build_dictionary {
my ($self) = @_;
Catmandu::Importer::CSV->new(
%{$self->csv_args},
file => $self->file,
header => 0,
fields => ['key', 'val'],
)->reduce(
{},
sub {
my ($dict, $pair) = @_;
$dict->{$pair->{key}} = $pair->{val};
$dict;
}
);
}

sub _build_fixer {
my ($self) = @_;

my $dict = $self->dictionary;

sub {
my $data = $_[0];

foreach my $k (keys %$dict) {
my $old_path = as_path($k);
my $new_path = as_path($dict->{$k});

my $getter = $old_path->getter;
my $deleter = $old_path->deleter;
my $creator = $new_path->creator;

my $values = [map {clone($_)} @{$getter->($data)}];
$deleter->($data);
$creator->($data, shift @$values) while @$values;
}

$data;
};
}

1;

__END__

=pod

=head1 NAME

Catmandu::Fix::map - move several fields by a lookup table

=head1 SYNOPSIS

# field_mapping.csv
# AU,author
# TI,title
# PU,publisher
# Y,year

# fields found in the field_mapping.csv will be replaced
# {AU => "Einstein"}
map(field_mapping.csv)
# {author => "Einstein"}

# values not found will be kept
# {foo => {bar => 232}}
map(field_mapping.csv)
# {foo => {bar => 232}}

# in case you have a different seperator
map(field_mapping.csv, sep_char: |)

=head1 SEE ALSO

L<Catmandu::Fix>, L<Catmandu::Fix::lookup>

=cut
43 changes: 43 additions & 0 deletions t/Catmandu-Fix-map.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env perl

use strict;
use warnings;
use Test::More;
use Test::Exception;
use Data::Dumper;

my $pkg;
my $pkg2;
BEGIN {
$pkg = 'Catmandu::Fix::map';
use_ok $pkg;
}

is_deeply $pkg->new('t/field_mapping.csv')
->fix({title => "Computational Biology"}),
{Title => "Computational Biology"}, "map simple field";

is_deeply $pkg->new('t/field_mapping.csv')->fix(
{
title => "Computational Biology",
author => "C. Ungewitter",
id => "3279423874"
}
),
{
Title => "Computational Biology",
Author => "C. Ungewitter",
Identifier => "3279423874"
},
"map several fields";

is_deeply $pkg->new('t/field_mapping.csv')->fix({publisher => "Springer"}),
{Publisher => [{nested => "Springer"}]}, "map nested field";

is_deeply $pkg->new('t/field_mapping.csv')->fix({publisher => "Springer"}),
{Publisher => [{nested => "Springer"}]}, "map nested field";

is_deeply $pkg->new('t/field_mapping.csv')->fix({deeply => {nested => ["XX"]}}),
{test => "XX", deeply => {nested => []}}, "map nested field";

done_testing;
5 changes: 5 additions & 0 deletions t/field_mapping.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
title,Title
author,Author
id,Identifier
publisher,Publisher.0.nested
deeply.nested.0,test