Skip to content

Commit

Permalink
Adding support for setting adding JSON paths
Browse files Browse the repository at this point in the history
  • Loading branch information
phochste committed Sep 30, 2015
1 parent ba88d05 commit f3903f3
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 36 deletions.
37 changes: 32 additions & 5 deletions lib/Catmandu/Fix/Inline/marc_add.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package Catmandu::Fix::Inline::marc_add;

use Clone qw(clone);
use Carp;
use Catmandu::Util qw(:is);
require Exporter;

@ISA = qw(Exporter);
Expand All @@ -24,8 +25,28 @@ sub marc_add {
my $code = $subfields[$i];
next unless length $code == 1;
my $value = $subfields[$i+1];
push @field , $code;
push @field , $value;

if ($value =~ /^\$\.(\S+)/) {
my $path = $1;
$value = Catmandu::Util::data_at($path,$data);
}

if (is_array_ref $value) {
for (@$value) {
push @field , $code;
push @field , $_;
}
}
elsif (is_hash_ref $value) {
for (keys %$value) {
push @field , $code;
push @field , $value->{$_};
}
}
else {
push @field , $code;
push @field , $value;
}
}

push @{ $ret->{record} } , \@field;
Expand All @@ -35,17 +56,23 @@ sub marc_add {

=head1 NAME
Catmandu::Fix::Inline::marc_map - A marc_map-er for Perl scripts
Catmandu::Fix::Inline::marc_add- A marc_add-er for Perl scripts
=head1 SYNOPSIS
use Catmandu::Fix::Inline::marc_add qw(:all);
my $data = marc_add($data,'245', a => 'value' );
# Set to a literal value
my $data = marc_add($data, '245', a => 'value');
# Set to a copy of a deeply nested JSON path
my $data = marc_add($data, '245', a => '$.my.deep.field');
=head1 SEE ALSO
L<Catmandu::Fix::Inline::marc_map> , L<Catmandu::Fix::Inline::marc_remove>
L<Catmandu::Fix::Inline::marc_set> ,
L<Catmandu::Fix::Inline::marc_map> ,
L<Catmandu::Fix::Inline::marc_remove>
=cut

Expand Down
4 changes: 3 additions & 1 deletion lib/Catmandu/Fix/Inline/marc_map.pm
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ Catmandu::Fix::Inline::marc_map - A marc_map-er for Perl scripts
=head1 SEE ALSO
L<Catmandu::Fix::Inline::marc_add> , L<Catmandu::Fix::Inline::marc_remove>
L<Catmandu::Fix::Inline::marc_set> ,
L<Catmandu::Fix::Inline::marc_add> ,
L<Catmandu::Fix::Inline::marc_remove>
=cut

Expand Down
4 changes: 3 additions & 1 deletion lib/Catmandu/Fix/Inline/marc_remove.pm
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ Catmandu::Fix::Inline::marc_remove - remove marc fields
=head1 SEE ALSO
L<Catmandu::Fix::Inline::marc_map> , L<Catmandu::Fix::Inline::marc_add>
L<Catmandu::Fix::Inline::marc_set> ,
L<Catmandu::Fix::Inline::marc_add> ,
L<Catmandu::Fix::Inline::marc_map>
=cut

Expand Down
132 changes: 132 additions & 0 deletions lib/Catmandu/Fix/Inline/marc_set.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package Catmandu::Fix::Inline::marc_set;

use Clone qw(clone);
use Carp;
use Catmandu::Util qw(:is);
require Exporter;

@ISA = qw(Exporter);
@EXPORT_OK = qw(marc_set);
%EXPORT_TAGS = (all => [qw(marc_set)]);

sub marc_set {
my ($data,$marc_path,$value) = @_;
my $record = $data->{record};

return $data unless defined $record;

if ($value =~ /^\$\.(\S+)/) {
my $path = $1;
$value = Catmandu::Util::data_at($path,$data);
}

if (is_array_ref $value) {
$value = $value->[-1];
}
elsif (is_hash_ref $value) {
my $last;
for (keys %$value) {
$last = $value->{$_};
}
$value = $last;
}

my $field_regex;
my ($field,$ind1,$ind2,$subfield_regex,$from,$to,$len);

if ($marc_path =~ /(\S{3})(\[(.)?,?(.)?\])?([_a-z0-9])?(\/(\d+)(-(\d+))?)?/) {
$field = $1;
$ind1 = $3;
$ind2 = $4;
if (defined $5) {
$subfield_regex = "$5";
}
else {
$subfield_regex = ($field =~ /^LDR|^00/) ? "_" : "a";
}
$from = $7;
$to = $9;
$len = defined $to ? $to - $from + 1 : 1;
}
else {
confess "invalid marc path";
}

$field_regex = $field;
$field_regex =~ s/\*/./g;

for (@$record) {
if ($_->[0] !~ /$field_regex/) {
next;
}

if (defined $ind1) {
if (!defined $_->[1] || $_->[1] ne $ind1) {
next;
}
}
if (defined $ind2) {
if (!defined $_->[2] || $_->[2] ne $ind2) {
next;
}
}

my $start;

if ($_->[0] =~ /^LDR|^00/) {
$start = 3;
}
elsif (defined $_->[5] && $_->[5] eq '_') {
$start = 5;
}
else {
$start = 3;
}

my $found = 0;
for (my $i = $start; $i < @$_; $i += 2) {

if ($_->[$i] eq $subfield_regex) {
if (defined $from) {
substr($_->[$i + 1], $from, $len) = $value;
}
else {
$_->[$i + 1] = $value;
}

$found = 1;
}
}

if ($found == 0) {
push(@$_,$subfield_regex,$value);
}

}

$data;
}

=head1 NAME
Catmandu::Fix::Inline::marc_set - A marc_set-er for Perl scripts
=head1 SYNOPSIS
use Catmandu::Fix::Inline::marc_set qw(:all);
# Set to literal value
my $data = marc_set($data,'245[1]a', 'value');
# Set to a copy of a deeply nested JSON path
my $data = marc_set($data,'245[1]a', '$.my.deep.field');
=head1 SEE ALSO
L<Catmandu::Fix::Inline::marc_add> ,
L<Catmandu::Fix::Inline::marc_remove> ,
L<Catmandu::Fix::Inline::marc_map>
=cut

1;
30 changes: 28 additions & 2 deletions lib/Catmandu/Fix/marc_add.pm
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package Catmandu::Fix::marc_add;

use Catmandu::Sane;
use Catmandu::Util qw(:is);
use Moo;
use Catmandu::Fix::Has;

Expand All @@ -25,8 +26,28 @@ sub fix {
my $code = $subfields[$i];
next unless length $code == 1;
my $value = $subfields[$i+1];
push @field , $code;
push @field , $value;

if ($value =~ /^\$\.(\S+)$/) {
my $path = $1;
$value = Catmandu::Util::data_at($path,$data);
}

if (is_array_ref $value) {
for (@$value) {
push @field , $code;
push @field , $_;
}
}
elsif (is_hash_ref $value) {
for (keys %$value) {
push @field , $code;
push @field , $value->{$_};
}
}
else {
push @field , $code;
push @field , $value;
}
}

push @{ $marc } , \@field;
Expand All @@ -43,10 +64,15 @@ Catmandu::Fix::marc_add - add new fields to marc
=head1 SYNOPSIS
# Set literal values
marc_add('900', a, 'test' , 'b', test)
marc_add('900', ind1 , ' ' , a, 'test' , 'b', test)
marc_add('900', ind1 , ' ' , a, 'test' , 'b', test , record:record2)
# Copy data from an other field (when the field value is an array, the
# subfield will be repeated)
marc_add('900', a, '$.my.data.field')
=head1 DESCRIPTION
Read our Wiki pages at L<https://github.com/LibreCat/Catmandu/wiki/Fixes> for a complete
Expand Down
28 changes: 26 additions & 2 deletions lib/Catmandu/Fix/marc_set.pm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ has record => (fix_opt => 1);
sub emit {
my ($self,$fixer) = @_;
my $record_key = $fixer->emit_string($self->record // 'record');
my $value = $fixer->emit_string($self->value);
my $marc_path = $self->marc_path;

my $field_regex;
Expand All @@ -36,11 +35,33 @@ sub emit {
confess "invalid marc path";
}

my $perl = "";

# Find out if we need to insert a literal value or a value from a JSON path
my $value;

if ($self->value =~ /^\$\.(\S+)$/) {
my $path = $fixer->split_path($1);
my $key = pop @$path;
$value = $fixer->generate_var;
$perl .= $fixer->emit_declare_vars($value, '""');
$perl .= $fixer->emit_walk_path($fixer->var, $path, sub {
my $var = shift;
$fixer->emit_get_key($var, $key, sub {
my $var = shift;
"${value} = ${var};";
});
});
}
else {
$value = $fixer->emit_string($self->value);
}
##############

$field_regex = $field;
$field_regex =~ s/\*/./g;

my $var = $fixer->var;
my $perl = "";

$perl .= $fixer->emit_foreach("${var}->{${record_key}}", sub {
my $var = shift;
Expand Down Expand Up @@ -114,6 +135,9 @@ Catmandu::Fix::marc_set - set a marc value of one (sub)field to a new value
# Set the 100-a subfield where indicator-1 is 3
marc_set('100[3]a','Farquhar family.')
# Copy data from another field in a subfield
marc_set('100a','$.my.deep.field')
=head1 DESCRIPTION
Read our Wiki pages at L<https://github.com/LibreCat/Catmandu/wiki/Fixes> for a complete
Expand Down
Loading

0 comments on commit f3903f3

Please sign in to comment.