File Coverage

blib/lib/Update/Immutable.pm
Criterion Covered Total %
statement 46 52 88.4
branch 34 48 70.8
condition n/a
subroutine 2 2 100.0
pod 0 1 0.0
total 82 103 79.6


line stmt bran cond sub pod time code
1             package Update::Immutable;
2              
3 1     1   15953 use common::sense;
  1         1  
  1         6  
4              
5             our $VERSION = '0.100';
6              
7             require Exporter;
8             our @ISA = qw(Exporter);
9             our @EXPORT_OK = qw(update);
10              
11              
12             ## A perl implementation of the update shipped with react, plus an $unset command, "correct" unshift ordering, and auto-vivification
13             ## https://facebook.github.io/react/docs/update.html
14              
15              
16             sub update {
17 33     33 0 14558 my ($view, $update) = @_;
18              
19 33 50       57 die "update is not a hash ref" if ref($update) ne 'HASH';
20              
21             ## Process commands:
22              
23 33 100       50 if (exists $update->{'$set'}) {
24 3         10 return $update->{'$set'};
25             }
26              
27 30 100       33 if (exists $update->{'$unset'}) {
28 2 100       4 $view = {} if !defined($view);
29 2 50       8 die "view is not a hash ref in unset" if ref($view) ne 'HASH';
30 2         4 my $new_view = { %$view };
31 2         4 delete $new_view->{$update->{'$unset'}};
32 2         4 return $new_view;
33             }
34              
35 28 100       33 if (exists $update->{'$merge'}) {
36 3 100       6 $view = {} if !defined($view);
37 3 50       5 die "view is not a hash ref in merge" if ref($view) ne 'HASH';
38 3 50       6 die "update is not a hash ref in merge" if ref($update->{'$merge'}) ne 'HASH';
39 3         3 return { %$view, %{ $update->{'$merge'} } };
  3         20  
40             }
41              
42 25 100       33 if (exists $update->{'$push'}) {
43 2 100       5 $view = [] if !defined($view);
44 2 50       5 die "view is not an array ref in push" if ref($view) ne 'ARRAY';
45 2         3 return [ @$view, @{ $update->{'$push'} } ];
  2         5  
46             }
47              
48 23 100       31 if (exists $update->{'$unshift'}) {
49 2 100       5 $view = [] if !defined($view);
50 2 50       5 die "view is not an array ref in unshift" if ref($view) ne 'ARRAY';
51 2         2 return [ @{ $update->{'$unshift'} }, @$view ];
  2         6  
52             }
53              
54 21 100       25 if (exists $update->{'$splice'}) {
55 4 100       6 $view = [] if !defined($view);
56 4 50       12 die "view is not an array ref in splice" if ref($view) ne 'ARRAY';
57 4 50       6 die "update is not an array ref in splice" if ref($update->{'$splice'}) ne 'ARRAY';
58              
59 4         11 my $new_view = [ @$view ];
60              
61 4         4 foreach my $s (@{ $update->{'$splice'} }) {
  4         16  
62 5 50       10 die "update element is not an array ref" if ref($s) ne 'ARRAY';
63 5         8 splice(@$new_view, $s->[0], $s->[1], @{$s}[2 .. @$s - 1]);
  5         12  
64             }
65              
66 4         10 return $new_view;
67             }
68              
69              
70             # Recurse to handle nested commands in $update:
71              
72 17 100       26 $view = {} if !defined($view);
73              
74 17 50       29 if (ref($view) eq 'HASH') {
    0          
75 17         23 my $output = { %$view };
76              
77 17         32 foreach my $k (keys %$update) {
78 17         39 $output->{$k} = update->($output->{$k}, $update->{$k});
79             }
80              
81 17         26 return $output;
82             } elsif (ref($view) eq 'ARRAY') {
83 0           my $output = [ @$view ];
84              
85 0           foreach my $k (keys %$update) {
86 0 0         die "non-numeric key in array update" if $k !~ /^\d+$/;
87 0           $output->[$k] = update->($output->[$k], $update->{$k});
88             }
89              
90 0           return $output;
91             }
92              
93 0           die "view not an array or hash";
94             }
95              
96              
97             1;
98              
99              
100              
101             __END__