File Coverage

blib/lib/Struct/Conditional.pm
Criterion Covered Total %
statement 136 139 97.8
branch 74 100 74.0
condition 42 68 61.7
subroutine 11 11 100.0
pod 5 7 71.4
total 268 325 82.4


line stmt bran cond sub pod time code
1             package Struct::Conditional;
2 14     14   876138 use 5.006; use strict; use warnings; our $VERSION = 0.03;
  14     14   164  
  14     14   71  
  14         25  
  14         373  
  14         73  
  14         23  
  14         675  
3 14     14   5846 use Clone qw/clone/;
  14         32345  
  14         20516  
4              
5             sub new {
6 15   50 15 1 3001 bless ($_[1] || {}), $_[0];
7             }
8              
9             sub compile {
10 15     15 1 76 my ($self, $struct, $params, $return_struct) = @_;
11 15         426 $struct = $self->itterate(clone($struct), $params);
12 15 50 33     167 die "failed to compile conditional json"
      33        
13             if (defined $struct && ! ref $struct && $struct eq 'compiled_null');
14 15         58 return $struct;
15             }
16              
17             sub itterate {
18 117     117 1 230 my ($self, $json, $params) = @_;
19 117         191 my $ref = ref $json;
20 117 100       273 if ($ref eq 'HASH') {
    100          
21 51         155 $json = $self->loops(
22             $self->conditionals($json, $params),
23             $params
24             );
25 51         73 for my $key ( keys %{$json} ) {
  51         141  
26 81         380 my $value = $self->itterate($json->{$key}, $params);
27             $value && $value eq 'compiled_null'
28             ? delete $json->{$key}
29 81 50 66     256 : do {
30 81         165 $json->{$key} = $value;
31             };
32             }
33 51 50       84 return keys %{$json} ? $json : 'compiled_null';
  51         190  
34             } elsif ($ref eq 'ARRAY') {
35 6         11 my $i = 0;
36 6         10 for my $item (@{ $json }) {
  6         15  
37 21         68 my $value = $self->itterate($item, $params);
38             $value && $value eq 'compiled_null'
39 21 50 33     93 ? do {
40 0         0 splice @{$json}, $i, 1;
  0         0  
41             }
42             : $i++;
43             }
44             }
45 66         137 return $self->make_replacement($json, $params);
46             }
47              
48             sub loops {
49 51     51 1 95 my ($self, $json, $params) = @_;
50             my %loops = map {
51 51         83 ($_ => delete $json->{$_})
  51         178  
52             } qw/for/;
53 51 100       113 if ($loops{for}) {
54 7         18 my $key = delete $loops{for}{key};
55 7 50       38 die "no key defined for loop" unless defined $key;
56 7 100       24 if ($loops{for}{each}) {
57 5         50 my @each = ();
58 5         14 my $map = delete $loops{for}{each};
59             die "param $key must be an arrayref"
60 5 50 50     69 unless (ref($params->{$key}) || "") eq 'ARRAY';
61 5         14 for (@{$params->{$key}}) {
  5         18  
62 20         326 my $jsn = $self->conditionals(clone($loops{for}), $_);
63 20 50       37 push @each, $self->make_replacement($jsn, $_) if scalar keys %{$jsn};
  20         77  
64             }
65 5 50       21 $json->{$map} = \@each if scalar @each;
66             }
67 7 100       35 if ($loops{for}{keys}) {
68 2         5 my %keys = ();
69 2         4 my $map = delete $loops{for}{keys};
70             die "param $key muse be an hashref"
71 2 50 50     11 unless (ref($params->{$key}) || "") eq 'HASH';
72 2         3 for my $k (keys %{$params->{$key}}) {
  2         10  
73             my $jsn = $self->conditionals(
74             clone($loops{for}),
75 8         176 $params->{$key}->{$k}
76             );
77 8 50       17 $keys{$k} = $self->make_replacement($jsn, $params->{$key}->{$k}) if scalar keys %{$jsn};
  8         27  
78             }
79 2 50       6 if (scalar %keys) {
80             $map =~ m/^1$/ ? do {
81 1         3 for my $k (keys %keys) {
82 4         7 $json->{$k} = $keys{$k};
83             }
84 2 100       10 } : do {
85 1         3 $json->{$map} = \%keys;
86             }
87             }
88             }
89             }
90 51         139 return $json;
91             }
92              
93             sub conditionals {
94 79     79 0 151 my ($self, $json, $params) = @_;
95             my %keywords = map {
96 79         140 ($_ => delete $json->{$_})
  316         611  
97             } qw/if elsif else given/;
98 79         125 my $expression;
99 79 100       168 if ($keywords{if}) {
100 26         79 ($expression) = $self->expressions($keywords{if}, $params);
101 26 100       67 unless ($expression) {
102 17 50       36 if ($keywords{elsif}) {
103 17         51 ($expression) = $self->expressions($keywords{elsif}, $params);
104             }
105 17 100       51 unless ($expression) {
106 7 50       22 if ($keywords{else}) {
107 7         15 ($expression) = $keywords{else}->{then};
108             }
109             }
110             }
111 26 50       54 if ($expression) {
112 26         38 $json->{$_} = $expression->{$_} for ( keys %{$expression} );
  26         100  
113             }
114             }
115 79 100       160 if ($keywords{given}) {
116 4 50       12 die "no key provided for given" if ! $keywords{given}{key};
117 4 50       11 die "no when provided for given" if ! ref $keywords{given}{when};
118 4         7 my $default = delete $keywords{given}{default};
119 4         9 my $ref = ref $keywords{given}{when};
120 4 100       11 if ($ref eq 'ARRAY') {
    50          
121 2         4 for (@{ $keywords{given}{when} }) {
  2         5  
122 4   33     18 $_->{key} ||= $keywords{given}{key};
123 4         19 ($expression) = $self->expressions($_, $params);
124 4 100       10 last if $expression;
125             }
126             } elsif ($ref eq 'HASH') {
127 2   33     13 $default ||= delete $keywords{given}{when}{default};
128 2         3 for my $k (keys %{ $keywords{given}{when} }) {
  2         9  
129             ($expression) = $self->expressions(
130             {
131             key => $keywords{given}{key},
132             m => $k,
133 3         26 then => $keywords{given}{when}{$k}
134             },
135             $params
136             );
137 3 100       13 last if $expression;
138             }
139             } else {
140 0         0 die "given cannot handle ref $ref";
141             }
142 4 100       13 $expression = $default if ! $expression;
143 4 50       16 if ($expression) {
144 4         8 $json->{$_} = $expression->{$_} for ( keys %{$expression} );
  4         19  
145             }
146             }
147 79         271 return $json;
148             }
149              
150             sub expressions {
151 56     56 1 101 my ($self, $keyword, $params) = @_;
152 56         94 my $success = 0;
153             $success = exists $params->{$keyword->{key}}
154 56 50       124 if defined $keyword->{exists};
155 56         105 my $key = $params->{$keyword->{key}};
156 56 50       98 if (defined $key) {
157             $success = $key =~ m/\Q$keyword->{m}\E/
158 56 100 66     668 if !$success && defined $keyword->{m};
159             $success = $key =~ m/\Q$keyword->{m}\E/i
160 56 50 66     224 if !$success && defined $keyword->{im};
161             $success = $key !~ m/\Q$keyword->{nm}\E/
162 56 50 66     167 if !$success && defined $keyword->{nm};
163             $success = $key !~ m/\Q$keyword->{nm}\E/i
164 56 50 66     194 if !$success && defined $keyword->{inm};
165             $success = $key eq $keyword->{eq}
166 56 100 100     160 if !$success && defined $keyword->{eq};
167             $success = $key ne $keyword->{ne}
168 56 100 100     218 if !$success && defined $keyword->{ne};
169             $success = $key > $keyword->{gt}
170 56 50 66     168 if !$success && defined $keyword->{gt};
171             $success = $key < $keyword->{lt}
172             if !$success && defined $keyword->{lt}
173 56 50 66     174 }
174 56 100 66     122 if ($keyword->{or} && !$success) {
175 2         4 $keyword->{or}->{then} = $keyword->{then};
176 2         9 ($success, $keyword) = $self->expressions($keyword->{or}, $params)
177             }
178 56 100 66     125 if ($keyword->{and} && $success) {
179 2         4 $keyword->{and}->{then} = $keyword->{then};
180 2         16 ($success, $keyword) = $self->expressions($keyword->{and}, $params)
181             }
182 56 100 66     122 if ($keyword->{elsif} && !$success) {
183 2         4 $keyword = $keyword->{elsif};
184 2         6 ($success, $keyword) = $self->expressions($keyword, $params);
185             }
186             ($success, $keyword) = ($keyword->{else}->{then}, $keyword->{else})
187 56 50 33     147 if ($keyword->{else} && !$success);
188 56 100       166 return (($success ? $keyword->{then} : 0), $keyword);
189             }
190              
191             sub make_replacement {
192 184     184 0 332 my ($self, $then, $params, $params_reg) = @_;
193 184   66     380 $params_reg ||= join "|", keys %{$params};
  94         311  
194 184   100     507 my $ref = ref $then || "";
195 184 100 100     1064 if ($ref eq 'HASH') {
    100          
    100          
196             $then->{$_} = $self->make_replacement($then->{$_}, $params, $params_reg)
197 49         55 for keys %{$then};
  49         194  
198             } elsif ($ref eq 'ARRAY') {
199 6         10 $then = [map { $self->make_replacement($_, $params, $params_reg) } @{ $then }];
  21         48  
  6         11  
200             } elsif (defined $then && $then =~ m/\{($params_reg)\}/) {
201 10         29 $then = $params->{$1};
202             }
203 184         497 return $then;
204             }
205              
206             1;
207              
208             __END__