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   841774 use 5.006; use strict; use warnings; our $VERSION = '1.00';
  14     14   147  
  14     14   64  
  14         25  
  14         368  
  14         74  
  14         30  
  14         651  
3 14     14   5640 use Clone qw/clone/;
  14         31069  
  14         19411  
4              
5             sub new {
6 15   50 15 1 2819 bless ($_[1] || {}), $_[0];
7             }
8              
9             sub compile {
10 15     15 1 76 my ($self, $struct, $params, $return_struct) = @_;
11 15         412 $struct = $self->itterate(clone($struct), $params);
12 15 50 33     156 die "failed to compile conditional json"
      33        
13             if (defined $struct && ! ref $struct && $struct eq 'compiled_null');
14 15         76 return $struct;
15             }
16              
17             sub itterate {
18 117     117 1 213 my ($self, $json, $params) = @_;
19 117         186 my $ref = ref $json;
20 117 100       267 if ($ref eq 'HASH') {
    100          
21 51         117 $json = $self->loops(
22             $self->conditionals($json, $params),
23             $params
24             );
25 51         72 for my $key ( keys %{$json} ) {
  51         121  
26 81         348 my $value = $self->itterate($json->{$key}, $params);
27             $value && $value eq 'compiled_null'
28             ? delete $json->{$key}
29 81 50 66     251 : do {
30 81         155 $json->{$key} = $value;
31             };
32             }
33 51 50       70 return keys %{$json} ? $json : 'compiled_null';
  51         155  
34             } elsif ($ref eq 'ARRAY') {
35 6         12 my $i = 0;
36 6         9 for my $item (@{ $json }) {
  6         16  
37 21         61 my $value = $self->itterate($item, $params);
38             $value && $value eq 'compiled_null'
39 21 50 33     92 ? do {
40 0         0 splice @{$json}, $i, 1;
  0         0  
41             }
42             : $i++;
43             }
44             }
45 66         123 return $self->make_replacement($json, $params);
46             }
47              
48             sub loops {
49 51     51 1 97 my ($self, $json, $params) = @_;
50             my %loops = map {
51 51         92 ($_ => delete $json->{$_})
  51         144  
52             } qw/for/;
53 51 100       118 if ($loops{for}) {
54 7         16 my $key = delete $loops{for}{key};
55 7 50       36 die "no key defined for loop" unless defined $key;
56 7 100       23 if ($loops{for}{each}) {
57 5         50 my @each = ();
58 5         12 my $map = delete $loops{for}{each};
59             die "param $key must be an arrayref"
60 5 50 50     54 unless (ref($params->{$key}) || "") eq 'ARRAY';
61 5         10 for (@{$params->{$key}}) {
  5         19  
62 20         306 my $jsn = $self->conditionals(clone($loops{for}), $_);
63 20 50       36 push @each, $self->make_replacement($jsn, $_) if scalar keys %{$jsn};
  20         67  
64             }
65 5 50       22 $json->{$map} = \@each if scalar @each;
66             }
67 7 100       36 if ($loops{for}{keys}) {
68 2         5 my %keys = ();
69 2         5 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         4 for my $k (keys %{$params->{$key}}) {
  2         8  
73             my $jsn = $self->conditionals(
74             clone($loops{for}),
75 8         177 $params->{$key}->{$k}
76             );
77 8 50       11 $keys{$k} = $self->make_replacement($jsn, $params->{$key}->{$k}) if scalar keys %{$jsn};
  8         31  
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       8 } : do {
85 1         3 $json->{$map} = \%keys;
86             }
87             }
88             }
89             }
90 51         104 return $json;
91             }
92              
93             sub conditionals {
94 79     79 0 158 my ($self, $json, $params) = @_;
95             my %keywords = map {
96 79         139 ($_ => delete $json->{$_})
  316         578  
97             } qw/if elsif else given/;
98 79         140 my $expression;
99 79 100       160 if ($keywords{if}) {
100 26         91 ($expression) = $self->expressions($keywords{if}, $params);
101 26 100       78 unless ($expression) {
102 17 50       39 if ($keywords{elsif}) {
103 17         49 ($expression) = $self->expressions($keywords{elsif}, $params);
104             }
105 17 100       46 unless ($expression) {
106 7 50       29 if ($keywords{else}) {
107 7         17 ($expression) = $keywords{else}->{then};
108             }
109             }
110             }
111 26 50       70 if ($expression) {
112 26         50 $json->{$_} = $expression->{$_} for ( keys %{$expression} );
  26         97  
113             }
114             }
115 79 100       149 if ($keywords{given}) {
116 4 50       9 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         8 my $ref = ref $keywords{given}{when};
120 4 100       11 if ($ref eq 'ARRAY') {
    50          
121 2         3 for (@{ $keywords{given}{when} }) {
  2         6  
122 4   33     19 $_->{key} ||= $keywords{given}{key};
123 4         19 ($expression) = $self->expressions($_, $params);
124 4 100       43 last if $expression;
125             }
126             } elsif ($ref eq 'HASH') {
127 2   33     9 $default ||= delete $keywords{given}{when}{default};
128 2         2 for my $k (keys %{ $keywords{given}{when} }) {
  2         7  
129             ($expression) = $self->expressions(
130             {
131             key => $keywords{given}{key},
132             m => $k,
133 3         30 then => $keywords{given}{when}{$k}
134             },
135             $params
136             );
137 3 100       10 last if $expression;
138             }
139             } else {
140 0         0 die "given cannot handle ref $ref";
141             }
142 4 100       10 $expression = $default if ! $expression;
143 4 50       13 if ($expression) {
144 4         6 $json->{$_} = $expression->{$_} for ( keys %{$expression} );
  4         15  
145             }
146             }
147 79         258 return $json;
148             }
149              
150             sub expressions {
151 56     56 1 110 my ($self, $keyword, $params) = @_;
152 56         90 my $success = 0;
153             $success = exists $params->{$keyword->{key}}
154 56 50       115 if defined $keyword->{exists};
155 56         142 my $key = $params->{$keyword->{key}};
156 56 50       99 if (defined $key) {
157             $success = $key =~ m/\Q$keyword->{m}\E/
158 56 100 66     632 if !$success && defined $keyword->{m};
159             $success = $key =~ m/\Q$keyword->{m}\E/i
160 56 50 66     218 if !$success && defined $keyword->{im};
161             $success = $key !~ m/\Q$keyword->{nm}\E/
162 56 50 66     179 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     151 if !$success && defined $keyword->{eq};
167             $success = $key ne $keyword->{ne}
168 56 100 100     220 if !$success && defined $keyword->{ne};
169             $success = $key > $keyword->{gt}
170 56 50 66     173 if !$success && defined $keyword->{gt};
171             $success = $key < $keyword->{lt}
172             if !$success && defined $keyword->{lt}
173 56 50 66     183 }
174 56 100 66     166 if ($keyword->{or} && !$success) {
175 2         5 $keyword->{or}->{then} = $keyword->{then};
176 2         10 ($success, $keyword) = $self->expressions($keyword->{or}, $params)
177             }
178 56 100 66     131 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     115 if ($keyword->{elsif} && !$success) {
183 2         4 $keyword = $keyword->{elsif};
184 2         336 ($success, $keyword) = $self->expressions($keyword, $params);
185             }
186             ($success, $keyword) = ($keyword->{else}->{then}, $keyword->{else})
187 56 50 33     129 if ($keyword->{else} && !$success);
188 56 100       175 return (($success ? $keyword->{then} : 0), $keyword);
189             }
190              
191             sub make_replacement {
192 184     184 0 343 my ($self, $then, $params, $params_reg) = @_;
193 184   66     360 $params_reg ||= join "|", keys %{$params};
  94         313  
194 184   100     431 my $ref = ref $then || "";
195 184 100 100     964 if ($ref eq 'HASH') {
    100          
    100          
196             $then->{$_} = $self->make_replacement($then->{$_}, $params, $params_reg)
197 49         54 for keys %{$then};
  49         204  
198             } elsif ($ref eq 'ARRAY') {
199 6         23 $then = [map { $self->make_replacement($_, $params, $params_reg) } @{ $then }];
  21         38  
  6         12  
200             } elsif (defined $then && $then =~ m/\{($params_reg)\}/) {
201 10         26 $then = $params->{$1};
202             }
203 184         457 return $then;
204             }
205              
206             1;
207              
208             __END__