File Coverage

blib/lib/Struct/Conditional.pm
Criterion Covered Total %
statement 137 140 97.8
branch 74 100 74.0
condition 42 68 61.7
subroutine 12 12 100.0
pod 5 8 62.5
total 270 328 82.3


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