File Coverage

blib/lib/Hades.pm
Criterion Covered Total %
statement 653 721 90.5
branch 210 272 77.2
condition 75 98 76.5
subroutine 93 119 78.1
pod 3 44 6.8
total 1034 1254 82.4


line stmt bran cond sub pod time code
1             package Hades;
2              
3 13     13   1664269 use 5.006;
  13         52  
4 13     13   77 use strict;
  13         23  
  13         499  
5 13     13   73 use warnings;
  13         31  
  13         2392  
6             our $VERSION = '0.26';
7 13     13   8277 use Module::Generate;
  13         7809400  
  13         3079  
8 13     13   7642 use Switch::Again qw/switch/;
  13         313795  
  13         133  
9 13     13   9083 use Hades::Myths { as_keywords => 1 };
  13         53  
  13         110  
10              
11             our ($PARENTHESES, $PARSE_PARAM_STRING);
12             BEGIN {
13 13     13   134 $PARENTHESES = qr{ \( ( (?: (?> [^()]+ ) | (??{ $PARENTHESES }) )* ) \) }x;
14 13         267213 $PARSE_PARAM_STRING = qr{ (^ (?: (?> [^(),]+ ) | (??{ $PARENTHESES }) )* ) \, }x;
15             }
16              
17             sub new {
18 19 100   19 0 118014 my ($class, %args) = (shift, scalar @_ == 1 ? %{$_[0]} : @_);
  11         82  
19 19 50       112 $args{macros} = {} if !$args{macros};
20 19 50       82 eval qq|require "Data::Dumper"| if $args{debug};
21 19         76 bless \%args, $class;
22             }
23              
24             sub verbose {
25 908     908 1 1435 my ($self, $verbose) = @_;
26 908 50       1719 if (defined $verbose) {
27 0         0 $self->{verbose} = !!$verbose;
28             }
29 908         11229 return $self->{verbose};
30             }
31              
32             sub debug {
33 908     908 1 1468 my ($self, $debug) = @_;
34 908 50       1734 if (defined $debug) {
35 0         0 $self->{debug} = !!$debug;
36             }
37 908         2952 return $self->{debug};
38             }
39              
40             sub debug_step {
41 908     908 0 1985 my ($self, $message, @debug) = @_;
42 908 50 33     1708 if ($self->debug || $self->verbose) {
43 0         0 $self->{debug_step}++;
44 0         0 my @caller = caller();
45 0         0 print "hades step $self->{debug_step} line $caller[2]: $message\n";
46 0 0       0 if ($self->debug) {
47 0         0 print Data::Dumper::Dumper $_ for (@debug);
48 0         0 print press_enter_to_continue . "\n";
49 0         0 my $ahh = <STDIN>;
50             }
51             }
52             }
53              
54             sub run {
55 12     12 1 309652 my ($class, $args) = @_;
56 12 50       65 $args->{eval} = _read_file($args->{file}) if $args->{file};
57 12         177 my $mg = Module::Generate->start;
58 12   66     203 $args->{$_} && $mg->$_($args->{$_}) for (qw/dist lib tlib author email version/);
59 12 100       221 if ($args->{realm}) {
60 1         4 $class = sprintf "Hades::Realm::%s", $args->{realm};
61 1         93 eval "require $class";
62             }
63 12         1399 my $self = $class->new($args);
64 12         76 $self->debug_step(sprintf(debug_step_1, $class), $args);
65 12 100       112 $self->can('module_generate') && $self->module_generate($mg, $class);
66 12         192 $self->debug_step(sprintf(debug_step_2, $class), $args->{eval});
67 12         37 my ($index, $ident, @lines, @line, @innerline, $nested) = (0, '');
68 12         76 while ($index <= length $self->{eval}) {
69 7344         11808 my $first_char = $self->index($index++);
70             $ident =~ m/^((:.*\()|(\{)|(\[))/
71             ? do {
72 5374         7436 my $copy = $ident;
73 5374         8313 $copy =~ s/\\\{|\\\}|\\\(|\\\)|\\\[|\\\]//g; # remove escaped
74 5374         57438 1 while ($copy =~ s/\([^()]*\)|\{[^{}]*\}|\[[^\[\]]*\]//g);
75             ($copy =~ m/\(|\{|\[|\)|\}|\]/) ? do {
76 5249         12121 $ident .= $first_char;
77 5374 100       12561 } : do {
78 125 50       264 if ($nested) {
79 125         258 push @innerline, $ident;
80             } else {
81 0         0 push @line, $ident;
82             }
83 125         310 $ident = '';
84             }
85             }
86             : ($first_char =~ m/\s/ && $ident !~ m/^$/)
87             ? (($nested)
88             ? ($ident =~ m/^(:|\$|\%|\@|\&)/) ? do {
89             push @innerline, $ident;
90             } : do {
91             push @line, [@innerline] if scalar @innerline;
92             @innerline = ($ident);
93             }
94             : do {
95             push @line, $ident;
96             }) && do { $ident = '' }
97             : ($first_char =~ m/\{/)
98             ? ! $nested ? $nested++ : do {
99 31 50       2404 push @innerline, $ident if $ident;
100 31         79 $ident = '{';
101             }
102             : ($first_char =~ m/\}/ && do { $nested--; 1; })
103             ? do{
104 17 50       121 push @line, [@innerline] if @innerline;
105 17 50       92 push @lines, [@line] if @line;
106 17         84 (@innerline, @line) = ((), ());
107             }
108 7344 100 100     24578 : do {
    100 33        
    100 66        
    100          
    100          
109 1748 100       5283 $ident .= $first_char unless $first_char =~ m/\s/;
110             };
111             }
112 12 50       1690 if (scalar @lines) {
113 12         92 $self->debug_step(sprintf(debug_step_3, scalar @lines), \@lines);
114 12         32 my $last_token;
115 12         36 for my $class (@lines) {
116 17 50       183 $self->can('before_class') && $self->before_class($mg, $class);
117 17         43 my $meta = {};
118 17         2457 for my $token (@{$self->build_class($mg, $class)}) {
  17         88  
119 80         263 $self->debug_step(debug_step_13, $token);
120             ! ref $token
121 8         23 ? do { $last_token = $self->build_class_inheritance($mg, $last_token, $token); }
122 72         1020 : scalar @{$token} == 1
123             ? $self->build_accessor_no_arguments($mg, $token, $meta)
124             : $token->[0] =~ m/^(synopsis|abstract|test)$/
125 80 50       245 ? do { my $m = "build_$1"; $self->$m($mg, $token, $meta); }
  3 100       14  
  3 100       17  
    50          
    100          
126             : $token->[1] =~ s/^{|}$//g
127             ? $self->build_sub_no_arguments($mg, $token, $meta)
128             : $token->[0] =~ m/^(our)$/
129             ? $self->build_our($mg, $token, $meta)
130             : $self->build_sub_or_accessor($mg, $token, $meta);
131             }
132 17 100       43 if (scalar keys %{$meta}) {
  17         70  
133 15         102 $self->build_new($mg, $meta);
134 15 100       168 $self->can('after_class') && $self->after_class($mg, $meta);
135 15         222 $self->debug_step(debug_step_35, $meta);
136             }
137             }
138 12         57 $self->debug_step(debug_step_36);
139             }
140 12 50       139 $self->can('before_generate') && $self->before_generate($mg);
141 12         68 $self->debug_step(debug_step_37);
142 12         107 $mg->generate;
143 12 50       64620981 $self->can('after_generate') && $self->after_generate($mg);
144             }
145              
146             sub build_class {
147 17     17 0 3178 my ($self, $mg, $class) = @_;
148 17         124 while ($class->[0] =~ m/^(dist|lib|tlib|realm|author|email|version)$/) {
149 0         0 $mg->$1($class->[1]);
150 0         0 $self->debug_step(sprintf(debug_step_4, $1, $class->[1]));
151 0         0 shift @{$class}, shift @{$class};
  0         0  
  0         0  
152             }
153 17 100       2404 if ($class->[0] eq 'macro') {
154 2         6 shift @{$class};
  2         5  
155 2         10 $self->debug_step(debug_step_5, $class);
156 2         11 $self->build_macro($mg, $class);
157 2         36 return [];
158             }
159 15         68 $self->debug_step(sprintf (debug_step_12, $class->[0]), $class);
160 15         33 $mg->class(shift @{$class})->new;
  15         142  
161 15         3466 return $class;
162             }
163              
164             sub build_new {
165 15     15 0 43 my ($self, $mg, $meta) = @_;
166 15         98 my %class = %Module::Generate::CLASS;
167 15         93 $self->debug_step(sprintf (debug_step_33, $class{CURRENT}{NAME}), $meta);
168 15         34 my $accessors = q|(|;
169             map {
170 46         81 $accessors .= qq|$_ => {|;
171 46 100       109 $accessors .= qq|required => 1,| if $meta->{$_}->{required};
172 46 100       4144 $accessors .= qq|default => $meta->{$_}->{default},| if $meta->{$_}->{default};
173             $accessors .= qq|builder => sub { my (\$self, \$value) = \@_;| . $self->build_builder($_, '$value', $meta->{$_}->{builder}) . qq|return \$value;}|
174 46 100       99 if $meta->{$_}->{builder};
175 46         108 $accessors .= qq|},|;
176 15         32 } grep { $meta->{$_}->{meta} eq 'ACCESSOR' } keys %{$meta};
  69         150  
  15         57  
177 15         39 $accessors .= q|)|;
178 15 100 100     108 my $new = $class{CURRENT}->{PARENT} || $class{CURRENT}->{BASE} ? 'my $self = $cls->SUPER::new(%args)' : 'my $self = bless {}, $cls';
179 15         47 my $code = qq|{
180             my (\$cls, \%args) = (shift(), scalar \@_ == 1 ? \%{\$_[0]} : \@_);
181             $new;
182             my \%accessors = $accessors;
183             for my \$accessor ( keys \%accessors ) {
184             my \$param = defined \$args{\$accessor} ? \$args{\$accessor} : \$accessors{\$accessor}->{default};
185             my \$value = \$self->\$accessor(
186             \$accessors{\$accessor}->{builder} ? \$accessors{\$accessor}->{builder}->(
187             \$self,
188             \$param
189             ) : \$param
190             );
191             unless (!\$accessors{\$accessor}->{required} \|\| defined \$value) {
192             die "\$accessor accessor is required";
193             }
194             }
195             return \$self;
196             }|;
197 15         47 $class{CURRENT}{SUBS}{new}{CODE} = $code;
198 15         264 $class{CURRENT}{SUBS}{new}{TEST} = [$self->build_tests('new', $meta, 'new', \%class)];
199 15         106 $self->debug_step(sprintf (debug_step_34, $class{CURRENT}{NAME}), $code);
200             }
201              
202             sub build_class_inheritance {
203 8     8 0 21 my ($self, $mg, $last_token, $token) = @_;
204             ($token =~ m/^(parent|base|require|use)$/) ? do {
205 4         15 $self->debug_step(sprintf(debug_step_14, $token), sprintf(debug_step_14_b, $token));
206 4         7 $last_token = $token;
207 8 100       45 } : do {
208 4         13 $self->debug_step(sprintf(debug_step_15, $last_token, $token));
209 4         26 $mg->$last_token($token);
210             };
211 8         64 return $last_token;
212             }
213              
214             sub build_accessor_no_arguments {
215 0     0 0 0 my ($self, $mg, $token, $meta) = @_;
216 0         0 $meta->{$token->[0]}->{meta} = 'ACCESSOR';
217 0         0 $self->debug_step(sprintf(debug_step_16, $token->[0]), $meta->{$token->[0]});
218 0         0 $mg->accessor($token->[0]);
219 0         0 return $meta;
220             }
221              
222             sub build_sub_no_arguments {
223 3     3 0 13 my ($self, $mg, $token, $meta) = @_;
224 3         7 my $name = shift @{$token};
  3         7  
225 3         14 $self->debug_step(sprintf(debug_step_18, $name), $meta->{$name});
226             $name =~ m/^(begin|unitcheck|check|init|end|new)$/
227 0         0 ? $mg->$name('{' . join( ' ', @{$token}) . '}')
228 3 50       26 : $mg->sub($name)->code($self->build_code($mg, $name, $self->build_sub_code($name, '', '', join ' ', @{$token})))
  3         59  
229             ->pod(qq|call $name method. Expects no params.|)->example(qq|\$obj->$name()|);
230 3         75 return $meta;
231             }
232              
233             sub build_our {
234 0     0 0 0 my ($self, $mg, $token, $meta) = @_;
235 0         0 my $name = shift @{$token};
  0         0  
236 0         0 $self->debug_step(debug_step_19, $token);
237 0         0 $mg->$name( '(' . join( ', ', @{$token}) . ')');
  0         0  
238 0         0 return $meta;
239             }
240              
241 1     1 0 5 sub build_synopsis { goto &build_synopsis_or_abstract; }
242              
243 1     1 0 4 sub build_abstract { goto &build_synopsis_or_abstract; }
244              
245             sub build_test {
246 1     1 0 5 my ($self, $mg, $token, $meta) = @_;
247 1         5 my ($name, $content) = @{$token};
  1         5  
248 1         1786 $self->debug_step(sprintf(debug_step_17, $name), $content);
249 1         78 $content =~ s/^\{\s*|\s*\}$//g;
250 1         125 $mg->class_tests(eval $content);
251 1         20 return $meta;
252             }
253              
254             sub build_synopsis_or_abstract {
255 2     2 0 6 my ($self, $mg, $token, $meta) = @_;
256 2         4 my ($name, $content) = @{$token};
  2         5  
257 2         7 $self->debug_step(sprintf(debug_step_17, $name), $content);
258 2         58 $content =~ s/^\{\s*|\s*\}$//g;
259 2         15 $mg->$name($content);
260 2         17 return $meta;
261             }
262              
263             sub build_sub_or_accessor_attributes {
264 69     69 0 149 my ($self, $name, $token, $meta) = @_;
265             my @ATTR = (
266             'default' => sub {
267 0     0   0 my $value = shift;
268 0         0 push @{$meta->{$name}->{caught}}, $value;
  0         0  
269             },
270             qr/^(\:around|\:ar)$/ => sub {
271 1     1   28 $meta->{$name}->{meta} = 'MODIFY';
272 1         9 $token->[-1] =~ s/^\{(.*)\}$/$1/sg;
273 1         3 $meta->{$name}->{around} = pop @{$token};
  1         5  
274             },
275             qr/^(\:after|\:a)$/ => sub {
276 2     2   54 $meta->{$name}->{meta} = 'MODIFY';
277 2         16 $token->[-1] =~ s/^\{(.*)\}$/$1/sg;
278 2         3 $meta->{$name}->{after} = pop @{$token};
  2         9  
279             },
280             qr/^(\:before|\:b)$/ => sub {
281 0     0   0 $meta->{$name}->{meta} = 'MODIFY';
282 0         0 $token->[-1] =~ s/^\{(.*)\}$/$1/sg;
283 0         0 $meta->{$name}->{before} = pop @{$token};
  0         0  
284             },
285             qr/^(:builder|:bdr)/ => sub {
286 1     1   24 my $value = shift;
287 1         2 $value =~ s/(\:bd|\:build)\((.*)\)$/$2/sg;
288 1 50       3 $meta->{$name}->{builder} = $2 ? $value : 1;
289             },
290             qr/^(\:clearer|\:c)$/ => sub {
291 12     12   492 $meta->{$name}->{clearer} = 1;
292             },
293             qr/^(\:coerce|\:co)/ => sub {
294 2     2   141 my $value = shift;
295 2         16 $value =~ s/(\:co|\:coerce)\((.*)\)$/$2/sg;
296 2         7 $meta->{$name}->{coerce} = $value;
297 2 100       9 if ($meta->{$name}->{params_map}) {
298             $meta->{$name}->{params_map}->{
299             $meta->{$name}->{param}->[-1]
300 1         7 }->{coerce} = $value;
301             }
302             },
303             qr/^(\:default|\:d)/ => sub {
304 22     22   1258 my $value = shift;
305 22         125 $value =~ s/.*\((.*)\)/$1/sg;
306 22 100       137 $value = '"' . $value . '"'
307             if $value !~ m/^(\{|\[|\"|\'|\$|\£|q)|(\d+)/;
308 22         68 $meta->{$name}->{default} = $value;
309 22 100       93 if ($meta->{$name}->{params_map}) {
310             $meta->{$name}->{params_map}->{
311             $meta->{$name}->{param}->[-1]
312 5         23 }->{default} = $value;
313             }
314             },
315             qr/^(\:example)/ => sub {
316 2     2   165 my $value = shift;
317 2         15 $value =~ s/^\:example\(\s*(.*)\s*\)$/$1/sg;
318 2         11 $meta->{$name}->{example} = $value;
319             },
320             qr/^(\:no_success_test)/ => sub {
321 0     0   0 $meta->{$name}->{no_success_test} = 1;
322             },
323             qr/^(\:pod)/ => sub {
324 2     2   169 my $value = shift;
325 2         14 $value =~ s/^:pod\(\s*(.*)\s*\)$/$1/sg;
326 2         9 $meta->{$name}->{pod} = $value;
327             },
328             qr/^(\:private|\:p)$/ => sub {
329 7     7   743 $meta->{$name}->{private} = 1;
330             },
331             qr/^(\:predicate|\:pr)$/ => sub {
332 9     9   763 $meta->{$name}->{predicate} = 1;
333             },
334             qr/^(\:required|\:r)$/ => sub {
335 12     12   1098 $meta->{$name}->{required} = 1;
336             },
337             qr/^(\:trigger|\:tr)/ => sub {
338 2     2   198 my $value = shift;
339 2         14 $value =~ s/(\:tr|\:trigger)\((.*)\)$/$2/sg;
340 2         10 $meta->{$name}->{trigger} = $value;
341             },
342             qr/^(\:test|\z)/ => sub {
343 2     2   201 my $value = shift;
344 2         16 $value =~ s/^(\:test|\:z)\(\s*(.*)\s*\)$/$2/sg;
345 2         3 push @{$meta->{$name}->{test}}, eval '(' . $value . ')';
  2         198  
346             },
347             qr/^(\:type|\:t)/ => sub {
348 62     62   7124 my $value = shift;
349 62         403 $value =~ s/.*\((.*)\)/$1/sg;
350 62         106 push @{$meta->{$name}->{type}}, $value;
  62         214  
351 62 100       289 if ($meta->{$name}->{params_map}) {
352             $meta->{$name}->{params_map}->{
353             $meta->{$name}->{param}->[-1]
354 21         124 }->{type} = $value;
355             }
356             },
357             qr/^(\{)/ => sub {
358 20     20   2161 my $value = shift;
359 20         365 $value =~ s/^\{|\}$//g;
360 20 50       87 $meta->{$name}->{meta} = 'METHOD' unless $meta->{$name}->{meta} eq 'MODIFY';
361 20         83 $meta->{$name}->{code} = $value;
362             },
363             qr/^(\%|\$|\@|\&)/ => sub {
364 26     26   3215 push @{$meta->{$name}->{param}}, $_[0];
  26         145  
365 26         122 $meta->{$name}->{params_map}->{$_[0]} = {};
366             }
367 69         3117 );
368 69         500 return @ATTR;
369             }
370              
371             sub build_sub_or_accessor {
372 72     72 0 171 my ($self, $mg, $token, $meta) = @_;
373 72         106 my $name = shift @{$token};
  72         158  
374 72 100       2235 if ($name =~ s/^\[(.*)\]$/$1/) {
375 3         1834 $self->debug_step(debug_step_20, $1);
376 3         16 $self->build_sub_or_accessor($mg, [$_, @{$token}], $meta) for split / /, $1;
  6         72  
377 3         14 return;
378             }
379 69         2760 $self->debug_step(sprintf(debug_step_21, $name), $token);
380 69         260 $meta->{$name}->{meta} = 'ACCESSOR';
381 69         189 my $switch = switch(
382             $self->build_sub_or_accessor_attributes($name, $token, $meta)
383             );
384 69         13021 $switch->(shift @{$token}) while scalar @{$token};
  253         1193  
  184         411  
385 69         233 $self->debug_step(sprintf(debug_step_22, $name), $meta->{$name});
386             $meta->{$name}->{meta} eq 'ACCESSOR'
387             ? $self->build_accessor($mg, $name, $meta)
388 69 100       412 : $meta->{$name}->{meta} eq 'MODIFY'
    100          
389             ? $self->build_modify($mg, $name, $meta)
390             : $self->build_sub($mg, $name, $meta);
391 69 100       256 $self->build_predicate($mg, $name, $meta) if $meta->{$name}->{predicate};
392 69 100       203 $self->build_clearer($mg, $name, $meta) if $meta->{$name}->{clearer};
393 69         3700 return $meta;
394             }
395              
396             sub build_accessor {
397 44     44 0 111 my ($self, $mg, $name, $meta) = @_;
398 44         126 $self->debug_step(sprintf(debug_step_23, $name), $meta->{$name});
399 44         264 my $private = $self->build_private($name, $meta->{$name}->{private});
400             my $type = $self->build_coerce($name, '$value', $meta->{$name}->{coerce})
401 44         188 . $self->build_type($name, $meta->{$name}->{type}[0]);
402 44         285 my $trigger = $self->build_trigger($name, '$value', $meta->{$name}->{trigger});
403 44         150 my $code = $self->build_code($mg, $name, $self->build_accessor_code($name, $private, $type, $trigger));
404 44         227 $mg->accessor($name)->code($code)->clear_tests->test($self->build_tests($name, $meta->{$name}));
405 44   66     1596 $meta->{$name}->{$_} && $mg->$_($self->replace_pe_string($meta->{$name}->{$_}, $name)) for qw/pod example/;
406 44         189 $self->debug_step(sprintf(debug_step_28, $name), $meta->{$name});
407             }
408              
409             sub build_accessor_code {
410 44     44 0 119 my ($self, $name, $private, $type, $trigger) = @_;
411 44         206 return qq|{
412             my ( \$self, \$value ) = \@_; $private
413             if ( defined \$value ) { $type
414             \$self->{$name} = \$value; $trigger
415             }
416             return \$self->{$name};
417             }|;
418             }
419              
420             sub replace_pe_string {
421 4     4 0 30 my ($self, $str, $name) = @_;
422 4         21 $str =~ s/\$name/$name/g;
423 4         19 return $str;
424             }
425              
426             sub build_modify {
427 3     3 0 9 my ($self, $mg, $name, $meta) = @_;
428 3         10 $self->debug_step(sprintf(debug_step_29, $name), $meta->{$name});
429 3   50     16 my $before_code = $meta->{$name}->{before} || "";
430 3   100     14 my $around_code = $meta->{$name}->{around} || qq|my \@res = \$self->\$orig(\@params);|;
431 3   100     40 my $after_code = $meta->{$name}->{after} || "";
432 3         12 my $code = $self->build_code($mg, $name, $self->build_modify_code($name, $before_code, $around_code, $after_code));
433 3         16 $mg->sub($name)->code($code)->pod(qq|call $name method.|)->test($self->build_tests($name, $meta->{$name}));
434 3   33     37 $meta->{$name}->{$_} && $mg->$_($self->replace_pe_string($meta->{$name}->{$_}, $name)) for qw/pod example/;
435 3         12 $self->debug_step(sprintf(debug_step_30, $name), $meta->{$name});
436             }
437              
438             sub build_modify_code {
439 3     3 0 11 my ($self, $name, $before_code, $around_code, $after_code) =@_;
440 3         16 return qq|{
441             my (\$orig, \$self, \@params) = ('SUPER::$name', \@_);
442             $before_code$around_code$after_code
443             return wantarray ? \@res : \$res[0];
444             }|;
445             }
446              
447             sub build_sub {
448 20     20 0 51 my ($self, $mg, $name, $meta) = @_;
449 20         88 my $code = $meta->{$name}->{code};
450 20         67 $self->debug_step(sprintf(debug_step_31, $name), $meta->{$name});
451 20         83 my ($params, $subtype, $params_explanation) = ( '', '', '' );
452             $subtype .= $self->build_private($name)
453 20 50       68 if $meta->{$name}->{private};
454 20 50       60 if ($meta->{$name}->{param}) {
455 20         33 for my $param (@{ $meta->{$name}->{param} }) {
  20         86  
456 26 100       67 $params_explanation .= ', ' if $params_explanation;
457 26         52 $params .= ', ' . $param;
458 26         157 my $pm = $meta->{$name}->{params_map}->{$param};
459             $subtype .= qq|$param = defined $param ? $param : $pm->{default};|
460 26 100       75 if ($pm->{default});
461 26         151 $subtype .= $self->build_coerce($name, $param, $pm->{coerce});
462 26 100       187 if ($pm->{type}) {
463 21 50       140 my $error_message = ($pm->{type} !~ m/^(Optional|Any|Item)/
464             ? qq|$param = defined $param ? $param : 'undef';| : q||)
465             . qq|die qq{$pm->{type}: invalid value $param for variable \\$param in method $name};|;
466             $subtype .= $self->build_type(
467             $name,
468             $pm->{type},
469             $param,
470             $error_message,
471 21 50       174 ($pm->{type} !~ m/^(Optional|Any|Item)/
472             ? qq|! defined($param) \|\|| : q||)
473             );
474 21         107 $params_explanation .= qq|param $param to be a $pm->{type}|;
475             } else {
476 5         14 $params_explanation .= qq|param $param to be any value including undef|;
477             }
478             }
479             }
480 20         66 $meta->{$name}->{params_explanation} = $params_explanation;
481 20         74 $code = $self->build_code($mg, $name, $self->build_sub_code($name, $params, $subtype, $code));
482 20         134 $params =~ s/^,\s*//;
483 20         59 my $example = qq|\$obj->$name($params)|;
484             $mg->sub($name)->code($code)
485             ->pod(qq|call $name method. Expects $params_explanation.|)
486             ->example($example)
487 20         105 ->test($self->build_tests($name, $meta->{$name}));
488 20   66     292 $meta->{$name}->{$_} && $mg->$_($self->replace_pe_string($meta->{$name}->{$_}, $name)) for qw/pod example/;
489 20         88 $self->debug_step(sprintf(debug_step_32, $name), $meta->{$name});
490             }
491              
492             sub build_code {
493 91     91 0 215 my ($self, $mg, $name, $code) = @_;
494 91         245 $self->debug_step(sprintf(debug_step_38, $name), $code);
495 91 50       227 return unless defined $code;
496 91         9999 1 while $code =~ s/€(\w+(|$PARENTHESES));/$self->build_macro_code($mg, $1)/ge;
  10         33  
497 91         631 $code =~ s/£(\w*(\s|\$|\-|\;|\,|\{|\}|\[|\]|\)|\(|\:))/$self->build_self($1)/eg;
  9         28  
498 91         297 $self->debug_step(sprintf(debug_step_44, $name), $code);
499 91         287 return $code;
500             }
501              
502             sub build_self {
503 9     9 0 33 my ($self, $name) = @_;
504 9         50 return qq|\$self->$name|;
505             }
506              
507             sub parse_params {
508 10     10 0 26 my ($self, $param_string) = @_;
509 10         18 my @params;
510 10         77 while ($param_string =~ s/$PARSE_PARAM_STRING//g) {
511 8         22 push @params, $self->minimise_param_string($1);
512             }
513 10         26 push @params, $self->minimise_param_string($param_string);
514 10         126 return @params;
515             }
516              
517             sub minimise_param_string {
518 18     18 0 39 my ($self, $string) = @_;
519 18 50       35 return $string unless length $string;
520 18         36 $string =~ s/^\s*\(\s*(.*)\s*\)\s*$/$1/sg;
521 18         82 $string =~ s/\s+/ /g;
522 18         480 $string =~ s/^\s*|\s*$//g;
523 18         141 $string =~ s/^q*(("|'|\||\/))((\\{2})*|(.*?[^\\](\\{2})*))\1$/$3/sg; # back compat
524 18         58 $string =~ s/q+(\{|\})((\\[\{\}])*|(.*?[^\\]([\{\}])*))\}/$2/sg; # back compat
525 18 50       40 return undef if $string =~ m/^undef$/;
526 18         67 return $string;
527             }
528              
529             sub build_macro_code {
530 10     10 0 34 my ($self, $mg, $match) = @_;
531 10         28 $self->debug_step(sprintf(debug_step_39, $match));
532 10 50       429 if ($match =~ m/^(.*)$PARENTHESES$/m) {
533 10         30 $self->debug_step(sprintf(debug_step_40, $1), $2);
534 10 50       42 return '' unless $self->{macros}->{$1}->{code};
535 10         22 $self->debug_step(sprintf(debug_step_41, $1), $self->{macros}->{$1}->{code});
536 10         28 my $v = $self->{macros}->{$1}->{code}->($self, $mg, $self->parse_params($2));
537 10         32 $self->debug_step(sprintf(debug_step_42, $1), $v);
538 10         1095 return $v;
539             }
540 0 0       0 return '' unless $self->{macros}->{$match}->{code};
541 0         0 $self->debug_step(sprintf(debug_step_43, $match), $self->{macros}->{$match}->{code});
542 0         0 my $v = $self->{macros}->{$match}->{code}->($self, $mg);
543 0         0 $self->debug_step(sprintf(debug_step_42, $match), $v);
544 0         0 return $v;
545             }
546              
547             sub build_sub_code {
548 23     23 0 72 my ($self, $name, $params, $subtype, $code) = @_;
549 23         102 return qq|{
550             my (\$self $params) = \@_; $subtype
551             $code;
552             }|;
553             }
554              
555             sub build_clearer {
556 12     12 0 115 my ($self, $mg, $name, $meta) = @_;
557 12         37 $self->debug_step(sprintf(debug_step_47, $name));
558             $mg->sub(qq|clear_$name|)
559             ->code($self->build_code($mg, $name, $self->build_clearer_code($name)))
560             ->pod(qq|clear $name accessor|)
561             ->example(qq|\$obj->clear_$name|)
562             ->test(
563 12         59 $self->build_tests($name, $meta->{$name}, "success"),
564             ['ok', qq|\$obj->clear_$name|],
565             ['is', qq|\$obj->$name|, 'undef']
566             );
567 12         151 $self->debug_step(sprintf(debug_step_48, $name));
568 12         27 return ($mg, $name, $meta);
569             }
570              
571             sub build_clearer_code {
572 12     12 0 205 my ($self, $name) = @_;
573 12         41 return qq|{
574             my (\$self) = \@_;
575             delete \$self->{$name};
576             return \$self;
577             }|;
578             }
579              
580             sub build_predicate {
581 9     9 0 29 my ($self, $mg, $name, $meta) = @_;
582 9         35 $self->debug_step(sprintf(debug_step_45, $name));
583             $mg->sub(qq|has_$name|)
584             ->code($self->build_code($mg, $name, $self->build_predicate_code($name)))
585             ->pod(qq|has_$name will return true if $name accessor has a value.|)
586             ->example(qq|\$obj->has_$name|)
587             ->test(
588             ['ok', qq|do{ delete \$obj->{$name}; 1;}|],
589             ['is', qq|\$obj->has_$name|, q|''|],
590 9         66 $self->build_tests($name, $meta->{$name}, 'success'),
591             ['is', qq|\$obj->has_$name|, 1],
592             );
593 9         134 $self->debug_step(sprintf(debug_step_46, $name));
594 9         24 return ($mg, $name, $meta);
595             }
596              
597             sub build_predicate_code {
598 9     9 0 153 my ($self, $name) = @_;
599 9         35 return qq|{
600             my (\$self) = \@_;
601             return exists \$self->{$name};
602             }|;
603             }
604              
605             sub build_builder {
606 1     1 0 2 my ($self, $name, $param, $code) = @_;
607 1 50       2 if (defined $code) {
608 1 50       4 $code = "_build_$name" if $code =~ m/^1$/;
609 1 50       6 return $code =~ m/^\w+$/
610             ? qq|$param = \$self->$code($param);|
611             : $code
612             }
613 0         0 return q||;
614             }
615              
616             sub build_coerce {
617 70     70 0 289 my ($self, $name, $param, $code) = @_;
618 70 100       165 if (defined $code) {
619 2 50       17 $code = $code =~ m/^\w+$/
620             ? qq|$param = \$self->$code($param);|
621             : $code;
622 2         7 $self->debug_step(sprintf(debug_step_25, $name), $code);
623 2         12 return $code;
624             }
625 68         238 return q||;
626             }
627              
628             sub build_trigger {
629 44     44 0 163 my ($self, $name, $param, $code) = @_;
630              
631 44 100       152 if (defined $code) {
632 1 50       9 $code = $code =~ m/^1$/
    50          
633             ? qq|\$self->_trigger_$name|
634             : $code =~ m/^\w+$/
635             ? qq|\$self->$code($param);|
636             : $code;
637 1         5 $self->debug_step(sprintf(debug_step_27, $name), $code);
638 1         3 return $code;
639             }
640 43         88 return q||;
641             }
642              
643             sub build_private {
644 44     44 0 154 my ($self, $name, $private) = @_;
645 44 100       121 if ($private) {
646 7         17 $private = qq|
647             my \$private_caller = caller();
648             if (\$private_caller ne __PACKAGE__) {
649             die \"cannot call private method $name from \$private_caller\";
650             }|;
651 7         24 $self->debug_step(sprintf(debug_step_24, $name), $private);
652 7         23 return $private;
653             }
654 37         75 return q||;
655             }
656              
657             sub build_type {
658 134     134 0 378 my ($self, $name, $type, $value, $error_string, $subcode, $code) = @_;
659 134   100     407 $value ||= '$value';
660 134   50     528 $code ||= '';
661 134   100     383 $subcode ||= '';
662 134 100       303 if ($type) {
663 129   66     383 $error_string ||= qq|die qq{$type: invalid value $value for accessor $name};|;
664             my $switch = switch
665             qr/^(Any)$/ => sub {
666 0     0   0 return '';
667             },
668             qr/^(Item)$/ => sub {
669 0     0   0 return '';
670             },
671             qr/^(Bool)$/ => sub {
672 1     1   35 return qq|
673             my \$ref = ref $value;
674             if ($subcode (\$ref \|\| 'SCALAR') ne 'SCALAR' \|\| (\$ref ? \$$value : $value) !~ m/^(1\|0)\$/) {
675             $error_string
676             }
677             $value = !!(\$ref ? \$$value : $value) ? 1 : 0;|;
678             },
679             qr/^(Str)$/ => sub {
680 37     24   1753 return qq|
681             if ($subcode ref $value) {
682             $error_string
683             }|;
684             },
685             qr/^(Num)$/ => sub {
686 0     0   0 return qq|
687             if ($subcode ref $value \|\| $value !~ m/^[-+\\d]\\d*\\.?\\d\*\$/) {
688             $error_string
689             }|;
690             },
691             qr/^(Int)$/ => sub {
692 27     24   1518 return qq|
693             if ($subcode ref $value \|\| $value !~ m/^[-+\\d]\\d\*\$/) {
694             $error_string
695             }|;
696             },
697             qr/^(Ref)$/ => sub {
698 0     0   0 return qq|
699             if (! ref $value) {
700             $error_string
701             }|;
702             },
703             qr/^(Ref\[(.*)\])$/ => sub {
704 0     0   0 my ($val, @matches) = @_;
705 0 0       0 $matches[1] = '"' . $matches[1] . '"' if $matches[1] =~ m/^[a-zA-Z]/;
706 0         0 return qq|
707             if ((ref($value) \|\| "") ne $matches[1]) {
708             $error_string
709             }|;
710             },
711             qr/^(ScalarRef)$/ => sub {
712 0     0   0 return qq|
713             if ((ref($value) \|\| "") ne "SCALAR") {
714             $error_string
715             }|;
716             },
717             qr/^(ScalarRef\[(.*)\])$/ => sub {
718 1     0   125 my ($val, @matches) = @_;
719 1 50       8 $matches[1] = '"' . $matches[1] . '"' if $matches[1] =~ m/^[a-zA-Z]/;
720 1         6 return qq|
721             if ((ref($value) \|\| "") ne $matches[1]) {
722             $error_string
723             }|;
724             },
725             qr/^(ArrayRef)$/ => sub {
726 1     1   87 return qq|
727             if ($subcode (ref($value) \|\| "") ne "ARRAY") {
728             $error_string
729             }|;
730             },
731             qr/^(ArrayRef\[(.*)\])$/ => sub {
732 21     4   2218 my ($val, @matches) = @_;
733 21   66     205 my $max = $matches[1] =~ s/\,\s*(\d+)\s*$// && $1;
734 21   66     133 my $min = $matches[1] =~ s/\,\s*(\d+)\s*$// && $1;
735 21         47 my $type = $matches[1];
736 21         64 @matches = ($type, $min, $max);
737 21         46 my $code = qq|
738             if ((ref($value) \|\| "") ne "ARRAY") {
739             $error_string
740             }|;
741 21         108 my $new_error_string = $self->extend_error_string($error_string, $value, '$item', qq| expected $matches[0]|, $matches[0]);
742 21 50       119 my $sub_code = $self->build_type($name, $matches[0], '$item', $new_error_string, ($matches[0] !~ m/^(Optional|Any|Item)/ ? qq|! defined(\$item) \|\|| : q||));
743 21 50       156 $code .= qq|
744             for my \$item (\@{ $value }) {$sub_code
745             }| if $sub_code;
746 21 100 66     122 $code .= qq|
747             my \$length = scalar \@{$value};|
748             if $matches[1] || $matches[2];
749 21 100       84 $code .= qq|
750             if (\$length < $matches[1]) {
751             die qq{$val for $name must contain atleast $matches[1] items}
752             }|
753             if $matches[1] !~ m/^$/;
754 21 100       138 $code .= qq|
755             if (\$length > $matches[2]) {
756             die qq{$val for $name must not be greater than $matches[2] items}
757             }|
758             if $matches[2] !~ m/^$/;
759 21         147 return $code;
760             },
761             qr/^(HashRef)$/ => sub {
762 8     8   1131 return qq|
763             if ((ref($value) \|\| "") ne "HASH") {
764             $error_string
765             }|;
766             },
767             qr/^(HashRef\[(.*)\])$/ => sub {
768 6     2   697 my ($val, @matches) = @_;
769 6         14 my $code = qq|
770             if ((ref($value) \|\| "") ne "HASH") {
771             $error_string
772             }|;
773              
774 6         26 my $new_error_string = $self->extend_error_string($error_string, $value, '$item', qq| expected $matches[1]|, $matches[1]);
775 6 50       35 my $sub_code = $self->build_type($name, $matches[1], '$item', $new_error_string, ($matches[1] !~ m/^(Optional|Any|Item)/ ? qq|! defined(\$item) \|\|| : q||));
776 6 50       53 $code .= qq|
777             for my \$item (values \%{ $value }) {$sub_code
778             }| if $sub_code;
779 6         27 return $code;
780             },
781             qr/^(CodeRef)$/ => sub {
782 1     0   126 return qq|
783             if ((ref($value) \|\| "") ne "CODE") {
784             $error_string
785             }|;
786             },
787             qr/^(RegexpRef)$/ => sub {
788 1     0   135 return qq|
789             if ((ref($value) \|\| "") ne "Regexp") {
790             $error_string
791             }|;
792             },
793             qr/^(GlobRef)$/ => sub {
794 1     0   142 return qq|
795             if ((ref($value) \|\| "") ne "GLOB") {
796             $error_string
797             }|;
798             },
799             qr/^(Object)$/ => sub {
800 4     3   468 return qq|
801             if ((ref($value) \|\| "") =~ m/^(\|HASH\|ARRAY\|SCALAR\|CODE\|GLOB)\$/) {
802             $error_string
803             }|;
804             },
805             qr/^(Map\[(.*)\])$/ => sub {
806 7     2   1063 my ($val, @matches) = @_;
807 7         30 @matches = map { my $h = $_; $h =~ s/^\s*|\s*//g; $h; } split ',', $matches[1], 2;
  14         24  
  14         178  
  14         88  
808 7         20 my $code = qq|
809             if ((ref($value) \|\| "") ne "HASH") {
810             $error_string
811             }|;
812 7         29 my $key_error_string = $self->extend_error_string($error_string, $value, '$key', qq| expected $matches[0]|);
813 7         28 my $key_sub_code = $self->build_type($name, $matches[0], '$key', $key_error_string);
814 7         22 $key_sub_code =~ s/ref \$key \|\| //;;
815 7         27 my $value_error_string = $self->extend_error_string($error_string, $value, '$val', qq| expected $matches[1]|, $matches[0]);
816 7 50       41 my $value_sub_code = $self->build_type($name, $matches[1], '$val', $value_error_string, ($matches[1] !~ m/^(Optional|Any|Item)/ ? qq|! defined(\$val) \|\|| : q||));
817 7 50 33     99 $code .= qq|
818             for my \$key (keys \%{ $value }) {
819             my \$val = ${value}->{\$key};$key_sub_code$value_sub_code
820             }| if $key_sub_code || $value_sub_code;
821 7         35 return $code;
822             },
823             qr/^(Tuple\[(.*)\])$/ => sub {
824 4     2   598 my ($val, @matches) = @_;
825 4         17 @matches = map { my $h = $_; $h =~ s/^\s*|\s*//g; $h; } split ',', $matches[1];
  16         28  
  16         140  
  16         86  
826 4         15 my $code = qq|
827             if ((ref($value) \|\| "") ne "ARRAY") {
828             $error_string
829             }|;
830 4         10 my $i = 0;
831 4         16 while (@matches) {
832 10         19 my ($match) = (shift @matches);
833 10 100       46 if ($match =~ m/(Map|Tuple|HashRef|ArrayRef|Dict)\[/) {
834             my $lame = sub {
835 6         14 my $copy = shift;
836 6         42 while ($copy =~ s/\[[^\[\]]+\]//g) {}
837 6 100       35 return ($copy =~ m/\[|\[/) ? 1 : 0;
838 4         17 };
839 4         14 while ($lame->($match .= ', ' . shift @matches)) {}
840             }
841 10         54 (my $new_value = $value) .= qq|->[$i]|;
842 10         39 my $item_error_string = $self->extend_error_string($error_string, $value, $new_value, qq| expected $match for index $i|, $match);
843 10 50       67 my $key_sub_code = $self->build_type($name, $match, $new_value, $item_error_string, ($match !~ m/^(Optional|Any|Item)/ ? qq|! defined($new_value) \|\|| : q||));
844 10         55 $code .= $key_sub_code;
845 10         37 $i++;
846             }
847 4         16 return $code;
848             },
849             qr/^(Dict\[(.*)\])$/ => sub {
850 5     4   647 my ($val, @matches) = @_;
851 5         23 @matches = split ',', $matches[1];
852 5         7 my $sub_code;
853 5         16 while (@matches) {
854 14         25 my ($match) = (shift @matches);
855 14 100 66     87 if (@matches && $match =~ m/(Map|Tuple|HashRef|ArrayRef|Dict)\[/) {
856             my $lame = sub {
857 23         34 my $copy = shift;
858 23         141 while ($copy =~ s/\[[^\[\]]+\]//g) {}
859 23 100       105 return ($copy =~ m/\[|\[/) ? 1 : 0;
860 6         22 };
861 6         21 while ($lame->($match .= ', ' . shift @matches)) {}
862             }
863 14         40 my ($k, $v) = map { my $h = $_; $h =~ s/^\s*|\s*$//g; $h; } split('=>', $match, 2);
  28         35  
  28         208  
  28         70  
864 14         33 (my $new_value = $value) .= qq|->{$k}|;
865 14         49 my $new_error_string = $self->extend_error_string($error_string, $value, $new_value, qq| expected $v for $k|, $v);
866 14 100       63 $sub_code .= $self->build_type($k, $v, $new_value, $new_error_string, ($v !~ m/^(Optional|Any|Item)/ ? qq|! defined($new_value) \|\|| : q||));
867             }
868 5         41 my $code = qq|
869             if ((ref($value) \|\| "") ne "HASH") {
870             $error_string
871             } $sub_code|;
872 5         21 return $code;
873             },
874             qr/^((Optional|Maybe)\[(.*)\])$/ => sub {
875 4     4   546 my ($val, @matches) = @_;
876 4         17 my $sub_code = $self->build_type($name, $matches[2], $value, $error_string);
877 4         10 my $code = qq|
878             if (defined $value) { $sub_code
879             }|;
880 4         15 return $code;
881 129         7663 };
882 129         20895 $code .= $switch->($type);
883 129         1041 $self->debug_step(sprintf(debug_step_26, $name), $code);
884             }
885 134         605 return $code;
886             }
887              
888             sub extend_error_string {
889 65     65 0 204 my ($self, $new_error_string, $value, $new_value, $message, $type) = @_;
890 65         175 my $old_type = quotemeta(qq|$value = defined $value ? $value : 'undef';|);
891 65         802 $new_error_string =~ s/^$old_type//;
892 65         666 $new_error_string =~ s/\Q$value\E/$new_value/;
893 65         307 $new_error_string =~ s/};$/$message};/;
894 65 100 100     348 if ($type && $type !~ m/^(Optional|Any|Item)/) {
895 54         147 $new_error_string = qq|$new_value = defined $new_value ? $new_value : 'undef';| . $new_error_string;
896             }
897 65         180 return $new_error_string;
898             }
899              
900             sub build_macro_attributes {
901 2     2 0 5 my ($self, $name, $token, $meta) = @_;
902             return (
903             'default' => sub {
904 0     0   0 my $value = shift;
905 0         0 push @{$meta->{$name}->{caught}}, $value;
  0         0  
906             },
907             qr/^(\:a|\:alias)/ => sub {
908 2     2   57 my $value = shift;
909 2         18 $value =~ s/^\:(a|alias)\(\s*(.*)\s*\)$/$2/sg;
910 2         3 push @{$meta->{$name}->{alias}}, split(' ', $value);
  2         15  
911             },
912             qr/^(\{)/ => sub {
913 2     2   72 my $value = shift;
914 2         59 $value =~ s/^\{|\}$//g;
915 2         306 $meta->{$name}->{code} = eval qq|sub { my (\$self, \$mg, \@params) = \@_; $value }|;
916             },
917 2         37 );
918             }
919              
920             sub build_macro {
921 2     2 0 6 my ($self, $mg, $class) = @_;
922 2         6 my $meta = $self->{macros};
923 2         4 for my $macro (@{$class}) {
  2         7  
924 4         17 $self->debug_step(debug_step_6, $macro);
925 4 100       23 if ($macro->[-1] !~ m/^{/) {
926 2         21 my $include = sprintf "Hades::Macro::%s", shift @{$macro};
  2         10  
927 2         9 $self->debug_step(sprintf(debug_step_7, $include), $macro);
928 2         256 eval qq|require $include|;
929 2 50       17 die $@ if $@;
930 2 100       22 my $include_meta = $include->new($macro->[0] ? do {
931 1         21 $macro->[0] =~ s/^\[|\]$//g;
932 1         89 ( eval qq|$macro->[0]| );
933             } : ())->meta;
934 2         31 $self->debug_step(sprintf(debug_step_8, $include), $include_meta);
935 2         4 $meta = {%{$meta}, %{$include_meta}};
  2         7  
  2         28  
936             } else {
937 2         5 my $name = shift @{$macro};
  2         7  
938 2         6 $self->debug_step(sprintf(debug_step_9, $name), $macro);
939 2         9 $meta->{$name}->{meta} = 'MACRO';
940 2         8 my $switch = switch(
941             $self->build_macro_attributes($name, $macro, $meta)
942             );
943 2         109 $switch->(shift @{$macro}) while scalar @{$macro};
  6         39  
  4         10  
944 2         9 $self->debug_step(sprintf(debug_step_10, $name), $meta->{$name});
945 2 50       8 if ($meta->{$name}->{alias}) {
946 2         5 for (@{$meta->{$name}->{alias}}) {
  2         7  
947 2         44 $meta->{$_} = $meta->{$name};
948             }
949             }
950             }
951             }
952 2         11 $self->debug_step(debug_step_11, $meta);
953 2         10 $self->{macros} = $meta;
954             }
955              
956             sub index {
957 7344     7344 0 10789 my ($self, $index) = @_;
958 7344         13699 return substr $self->{eval}, $index, 1;
959             }
960              
961             sub build_test_data {
962 276     276 0 662 my ($self, $type, $name, $required) = @_;
963             my $switch = switch
964             qr/^(Any)$/ => sub {
965 15     15   371 return $self->_generate_test_string;
966             },
967             qr/^(Item)$/ => sub {
968 0     0   0 return $self->_generate_test_string;
969             },
970             qr/^(Bool)$/ => sub {
971 2     2   71 return (q|1|, q|[]|, q|{}|);
972             },
973             qr/^(Str)$/ => sub {
974 73     47   2916 return ($self->_generate_test_string, q|[]|, q|\1|);
975             },
976             qr/^(Num)$/ => sub {
977 0     0   0 return (q|100.555|, q|[]|, $self->_generate_test_string);
978             },
979             qr/^(Int)$/ => sub {
980 62     56   3361 return (q|10|, q|[]|, $self->_generate_test_string);
981             },
982             qr/^(Ref)$/ => sub {
983 0     0   0 return (q|{ test => 'test' }|, $self->_generate_test_string, q|1|);
984             },
985             qr/^(Ref\[(.*)\])$/ => sub {
986 0     0   0 my ($val, @matches) = @_;
987 0 0       0 $matches[1] = '"' . $matches[1] . '"' if $matches[1] =~ m/^[a-zA-Z]/;
988             return (
989 0         0 qq|bless({ test => 'test' }, $matches[1])|,
990             qq|bless({ test => 'test' }, $matches[1] . 'Error')|,
991             $self->_generate_test_string
992             );
993             },
994             qr/^(ScalarRef)$/ => sub {
995 0     0   0 return ( q|\1|, 1, q|[]|);
996             },
997             qr/^(ScalarRef\[(.*)\])$/ => sub {
998 2     0   173 my ($val, @matches) = @_;
999 2 50       11 $matches[1] = '"' . $matches[1] . '"' if $matches[1] =~ m/^[a-zA-Z]/;
1000             return (
1001 2         10 qq|do { my \$okay = ''; bless( \\\$okay, $matches[1]) }|,
1002             qq|do { my \$okay = ''; bless( \\\$okay, $matches[1] . 'Error') }|,
1003             $self->_generate_test_string,
1004             q|{}|
1005             );
1006             },
1007             qr/^(ArrayRef)$/ => sub {
1008             return (
1009 2     2   172 qq|['test']|,
1010             qq|{}|,
1011             $self->_generate_test_string
1012             );
1013             },
1014             qr/^(ArrayRef\[(.*)\])$/ => sub {
1015 42     8   4222 my ($val, @matches) = @_;
1016 42   66     393 my $max = $matches[1] =~ s/\,\s*(\d+)\s*$// && $1;
1017 42   66     310 my $min = $matches[1] =~ s/\,\s*(\d+)\s*$// && $1;
1018 42         86 my $type = $matches[1];
1019 42         125 @matches = ($type, $min, $max);
1020 42         148 my @values = $self->build_test_data($matches[0], $name, $required);
1021 42 50       2912 push @values, 'undef' unless $matches[0] =~ m/^Optional/;
1022             return (
1023             (map {
1024 318         539 my $v = $_;
1025 318   100     2124 sprintf q|[ %s ]|, join ", ", map { $v } 0 .. ($matches[1] || 1) - 1;
  372         1274  
1026             } @values),
1027             (($matches[1] || 0) > 0 ? (
1028             qq|[]|
1029             ) : ( )),
1030             ($matches[2] ? (
1031 42 100 100     120 sprintf q|[ %s ]|, join ", ", map { $values[0] } 0 .. $matches[2] + 1
  744 100       1257  
1032             ) : ( )),
1033             q|{}|,
1034             $self->_generate_test_string
1035             );
1036             },
1037             qr/^(HashRef)$/ => sub {
1038             return (
1039 11     11   1030 q|{ 'test' => 'test' }|,
1040             q|[]|,
1041             $self->_generate_test_string
1042             );
1043             },
1044             qr/^(HashRef\[(.*)\])$/ => sub {
1045 12     4   1450 my ($val, @matches) = @_;
1046 12         68 my @values = $self->build_test_data($matches[1], $name, $required);
1047 12 50       877 push @values, 'undef' unless $matches[1] =~ qr/^Optional/;
1048             return (
1049             (map {
1050 12         34 sprintf q|{ test => %s }|, $_;
  114         237  
1051             } @values),
1052             q|[]|,
1053             $self->_generate_test_string
1054             );
1055             },
1056             qr/^(CodeRef)$/ => sub {
1057             return (
1058 2     0   291 q|$sub|,
1059             q|[]|,
1060             $self->_generate_test_string
1061             );
1062             },
1063             qr/^(RegexpRef)$/ => sub {
1064             return (
1065 2     0   270 q|qr/abc/|,
1066             q|[]|,
1067             $self->_generate_test_string
1068             );
1069             },
1070             qr/^(GlobRef)$/ => sub {
1071             return (
1072 2     0   302 q|$globref|,
1073             q|[]|,
1074             $self->_generate_test_string
1075             );
1076             },
1077             qr/^(Object)$/ => sub {
1078             return (
1079 5     3   594 q|bless({}, 'Test')|,
1080             q|[]|,
1081             $self->_generate_test_string
1082             );
1083             },
1084             qr/^(Map\[(.*)\])$/ => sub {
1085 14     4   2126 my ($val, @matches) = @_;
1086 14         55 @matches = map { my $h = $_; $h =~ s/^\s*|\s*//g; $h; } split ',', $matches[1], 2;
  28         46  
  28         375  
  28         86  
1087 14         59 my @keys = $self->build_test_data($matches[0], $name, $required);
1088 14         1005 my @values = $self->build_test_data($matches[1], $name, $required);
1089 14 50       914 push @values, 'undef' unless $matches[1] =~ m/^Optional/;
1090             return (
1091             (map {
1092 14         35 sprintf q|{ %s => %s }|, $keys[0], $_;
  104         258  
1093             } @values),
1094             q|[]|,
1095             $self->_generate_test_string
1096             );
1097             },
1098             qr/^(Tuple\[(.*)\])$/ => sub {
1099 8     4   1343 my ($val, @matches) = @_;
1100 8         40 @matches = map { my $h = $_; $h =~ s/^\s*|\s*//g; $h; } split ',', $matches[1];
  32         79  
  32         320  
  32         79  
1101 8         19 my @tuple;
1102 8         26 while (@matches) {
1103 20         859 my ($match) = (shift @matches);
1104 20 100       103 if ($match =~ m/(Map|Tuple|HashRef|ArrayRef|Dict)\[/) {
1105             my $lame = sub {
1106 12         24 my $copy = shift;
1107 12         84 while ($copy =~ s/\[[^\[\]]+\]//g) {}
1108 12 100       65 return ($copy =~ m/\[|\[/) ? 1 : 0;
1109 8         31 };
1110 8         30 while ($lame->($match .= ', ' . shift @matches)) {}
1111             }
1112 20 50       60 push @tuple, [
1113             $self->build_test_data($match, $name, $required), ($_ =~ m/^Optional/ ? () : 'undef')
1114             ];
1115             }
1116 8         482 my $d = 0;
1117             return (
1118             (map {
1119 8         16 my ($tup, $m) = ($_, 0, $d++);
  20         46  
1120             map {
1121 124         195 my $ah = $_;
1122             $m++ == 0 && $d > 1 ? () :
1123 124 100 100     353 sprintf q|[ %s ]|, join ', ', map {$d - 1 == $_ ? $ah : $tuple[$_]->[0] } 0 .. $#tuple;
  308 100       862  
1124 20         30 } @{$tup};
  20         38  
1125             } @tuple),
1126             q|[]|,
1127             q|{}|,
1128             $self->_generate_test_string
1129             );
1130             },
1131             qr/^(Dict\[(.*)\])$/ => sub {
1132 14     12   1925 my ($val, @matches) = @_;
1133 14         62 @matches = split ',', $matches[1];
1134 14         19 my %map;
1135 14         37 while (@matches) {
1136 34         58 my ($match) = (shift @matches);
1137 34 100 100     194 if (@matches && $match =~ m/(Map|Tuple|ArrayRef|Dict)\[/) {
1138             my $lame = sub {
1139 46         71 my $copy = shift;
1140 46         306 while ($copy =~ s/\[[^\[\]]+\]//g) {}
1141 46 100       219 return ($copy =~ m/\[|\[/) ? 1 : 0;
1142 12         45 };
1143 12         46 while ($lame->($match .= ', ' . shift @matches)) {}
1144             }
1145 34         94 my ($k, $v) = map { my $h = $_; $h =~ s/^\s*|\s*$//g; $h; } split('=>', $match, 2);
  68         93  
  68         522  
  68         154  
1146 34         87 $v =~ s/,\s*$//;
1147 34         81 my @values = $self->build_test_data($v, $name, $required);
1148 34 100       1866 push @values, 'undef' unless $v =~ m/^Optional/;
1149 34         86 $map{$k} = \@values;
1150 34         40 push @{ $map{_dict_columns} }, $k;
  34         135  
1151             }
1152 14         40 my $d = 0;
1153             return (
1154             (map {
1155 34         63 my ($dict, $m) = ($_, 0, $d++);
1156             map {
1157 290         496 my $ah = $_;
1158             $m++ == 0 && $d > 1 ? () :
1159 290 100 100     698 sprintf q|{ %s }|, join ', ', map {$dict eq $_ ? qq|$_ => $ah| : sprintf( q|%s => %s|, $_, $map{$_}->[0]) } @{$map{_dict_columns}};
  680 100       1653  
  270         412  
1160 34         40 } @{$map{$dict}};
  34         91  
1161 14         19 } @{$map{_dict_columns}}), q|{}|, q|[]|, $self->_generate_test_string
  14         24  
1162             );
1163             },
1164             qr/^((Optional|Maybe)\[(.*)\])$/ => sub {
1165 8     8   1133 my ($val, @matches) = @_;
1166 8         27 my @values = $self->build_test_data($matches[2], $name, $required);
1167 8 100       440 $values[0] = 'undef' unless $required;
1168 8         29 return @values;
1169 276         12671 };
1170 276         49544 return $switch->($type);
1171             }
1172              
1173             sub build_tests {
1174 105     105 0 10672 my ($self, $name, $meta, $mod, $class) = @_;
1175 105         212 my @tests = ();
1176             $mod ? $mod ne 'new' ? do {
1177 21   100     101 my ($valid) = $self->build_test_data($meta->{type}->[0] || 'Any', $name);
1178 21         1480 push @tests, ['deep', qq|\$obj->$name($valid)|, $valid];
1179             } : do {
1180 15         31 my %test_data;
1181             map {
1182 46 50       2479 unless ($meta->{$_}->{no_success_test}) {
1183 46         70 push @{$test_data{test_data_columns}}, $_;
  46         110  
1184 46 100       229 $test_data{$_} = [ $self->build_test_data($meta->{$_}->{type}->[0] ? $meta->{$_}->{type}->[0] : 'Any', '', 1) ]
1185             }
1186 15         29 } grep { $meta->{$_}->{meta} eq 'ACCESSOR' } keys %{$meta};
  69         134  
  15         47  
1187 15         847 my $valid = join(', ', map { sprintf '%s => %s', $_, $test_data{$_}->[0] } grep { $meta->{$_}->{required} } @{$test_data{test_data_columns}});
  12         40  
  46         98  
  15         52  
1188             push @tests, [
1189             'ok',
1190             sprintf(
1191             'my $obj = %s->new({%s})',
1192             $class->{CURRENT}->{NAME},
1193             $valid
1194             )
1195             ], [
1196             'ok',
1197             sprintf(
1198             '$obj = %s->new(%s)',
1199             $class->{CURRENT}->{NAME},
1200 15         124 $valid
1201             )
1202             ], ['isa_ok', '$obj', qq|'$class->{CURRENT}->{NAME}'|];
1203 15         31 my $d = 0;
1204 15         28 for my $key (@{$test_data{test_data_columns}}) {
  15         47  
1205 46 100       162 if ($meta->{$key}->{default}) {
    100          
1206 17 100       27 $valid = join(', ', map { $key ne $_ ? ( sprintf '%s => %s', $_, $test_data{$_}->[0] ) : () } @{$test_data{test_data_columns}});
  84         206  
  17         54  
1207             push @tests, [
1208             'ok',
1209             sprintf(
1210             '$obj = %s->new({%s})',
1211             $class->{CURRENT}->{NAME},
1212             $valid
1213             ),
1214             ], [
1215             'ok',
1216             sprintf(
1217             '$obj = %s->new(%s)',
1218             $class->{CURRENT}->{NAME},
1219             $valid
1220             ),
1221 17         136 ], [ 'deep', qq|\$obj->$key|, $meta->{$key}->{default} ];
1222             } elsif ($meta->{$key}->{required}) {
1223             push @tests, [
1224             'eval',
1225             sprintf(
1226             '$obj = %s->new({%s})',
1227             $class->{CURRENT}->{NAME},
1228 3 100       10 join(', ', map { $key ne $_ ? ( sprintf '%s => %s', $_, $test_data{$_}->[0] ) : () } @{$test_data{test_data_columns}})
  24         58  
  3         8  
1229             ),
1230             'required'
1231             ];
1232             }
1233 46         75 my $m = 0;
1234 46         64 for my $ah (@{$test_data{$key}}) {
  46         88  
1235 349 100       593 if ($m++ == 0) {
1236 46 100       108 next if $d > 0;
1237             push @tests, [
1238             'ok',
1239             sprintf q|$obj = %s->new({ %s })|,
1240             $class->{CURRENT}->{NAME},
1241 11 100       31 join ', ', map {$key eq $_ ? qq|$_ => $ah| : sprintf( q|%s => %s|, $_, $test_data{$_}->[0]) } @{$test_data{test_data_columns}}
  46         181  
  11         24  
1242             ];
1243             } else {
1244             push @tests, [
1245             'eval',
1246             sprintf(
1247             q|$obj = %s->new({ %s })|,
1248             $class->{CURRENT}->{NAME},
1249 303 100       435 join ', ', map {$key eq $_ ? qq|$_ => $ah| : sprintf( q|%s => %s|, $_, $test_data{$_}->[0]) } @{$test_data{test_data_columns}}
  2892         7256  
  303         502  
1250             ),
1251             'invalid|type|constraint|greater|atleast'
1252             ];
1253             }
1254             }
1255 46         154 $d++;
1256             }
1257             } : $meta->{meta} eq 'ACCESSOR' ? do {
1258 46         143 push @tests, ['can_ok', qq|\$obj|, qq|'$name'|];
1259             $meta->{private} ? do {
1260 7         24 push @tests, ['eval', qq|\$obj->$name|, 'private method|private attribute'];
1261 46 100       128 } : do {
1262 39 100 66     359 push @tests, ['is', qq|\$obj->$name|, 'undef'] if !$meta->{no_success_test} && !$meta->{builder} && !$meta->{required} && !$meta->{default};
      100        
      100        
1263 39   100     249 my (@test_cases) = $self->build_test_data($meta->{type}->[0] || 'Any', $name, $meta->{required} || $meta->{builder});
      100        
1264 39 100       2613 if (scalar @test_cases > 1) {
1265 35         69 my $valid = shift @test_cases;
1266 35 50       167 push @tests, ['deep', qq|\$obj->$name($valid)|, $valid] unless $meta->{no_success_test};
1267 35 50       87 unless ($meta->{coerce}) {
1268 35         74 for (@test_cases) {
1269 291         667 push @tests, ['eval', qq|\$obj->$name($_)|, 'invalid|value|type|constraint|greater|atleast' ];
1270             }
1271             }
1272 35 50       167 push @tests, ['deep', qq|\$obj->$name|, $valid] unless $meta->{no_success_test};
1273             }
1274             };
1275 105 100       388 } : do {
    100          
    100          
    100          
1276             $meta->{private} ? do {
1277 0         0 push @tests, ['eval', qq|\$obj->$name|, 'private method'];
1278 23 50 66     110 } : $meta->{param} && do {
    100          
1279             my %test_data = map {
1280             $_ => [
1281             $self->build_test_data($meta->{params_map}->{$_}->{type} || 'Any', $name), ($meta->{params_map}->{$_}->{type} || 'Any') !~ m/^(|Optional|Any|Item)/ ? q|undef| : ()
1282             ]
1283             } @{ $meta->{param} };
1284             for my $key (@{$meta->{param}}) {
1285             for my $ah (splice @{$test_data{$key}}, 1) {
1286             push @tests, [
1287             'eval',
1288             sprintf(
1289             q|$obj->%s(%s)|,
1290             $name,
1291             join ', ', map {$key eq $_ ? $ah : $test_data{$_}->[0]} @{$meta->{param}}
1292             ),
1293             'invalid|value|type|constraint|greater|atleast'
1294             ];
1295             }
1296             }
1297             }
1298             };
1299 105 100       338 push @tests, @{$meta->{test}} if $meta->{test};
  2         5  
1300 105         617 return @tests;
1301             }
1302              
1303             sub _read_file {
1304 0     0   0 my ($file) = @_;
1305 0         0 open my $fh, '<', $file;
1306 0         0 my $content = do { local $/; <$fh>; };
  0         0  
  0         0  
1307 0         0 close $fh;
1308 0         0 return $content;
1309             }
1310              
1311             sub _generate_test_string {
1312 266     266   939 my @data = qw/penthos curae nosoi geras phobos limos aporia thanatos algea hypnos gaudia/;
1313 266         3659 return sprintf q|'%s'|, $data[int(rand(scalar @data))];
1314             }
1315              
1316             1;
1317              
1318             __END__
1319              
1320             =head1 NAME
1321              
1322             Hades - Less is more, more is less!
1323              
1324             =head1 VERSION
1325              
1326             Version 0.26
1327              
1328             =cut
1329              
1330             =head1 SYNOPSIS
1331              
1332             For how the other modules in the distribution are generated see the .hades files in the root directory.
1333              
1334             use Hades;
1335              
1336             Hades->run({
1337             eval => q|
1338             Kosmos {
1339             [penthos curae] :t(Int) :d(2) :p :pr :c :r
1340             geras $nosoi :t(Int) :d(2) {
1341             if (£penthos == $nosoi) {
1342             return £curae;
1343             }
1344             }
1345             }
1346             |
1347             });
1348              
1349             ... generates ...
1350              
1351             package Kosmos;
1352             use strict;
1353             use warnings;
1354             our $VERSION = 0.01;
1355              
1356             sub new {
1357             my ( $cls, %args ) = ( shift(), scalar @_ == 1 ? %{ $_[0] } : @_ );
1358             my $self = bless {}, $cls;
1359             my %accessors = (
1360             penthos => { required => 1, default => 2, },
1361             curae => { required => 1, default => 2, },
1362             );
1363             for my $accessor ( keys %accessors ) {
1364             my $value
1365             = $self->$accessor(
1366             defined $args{$accessor}
1367             ? $args{$accessor}
1368             : $accessors{$accessor}->{default} );
1369             unless ( !$accessors{$accessor}->{required} || defined $value ) {
1370             die "$accessor accessor is required";
1371             }
1372             }
1373             return $self;
1374             }
1375              
1376             sub penthos {
1377             my ( $self, $value ) = @_;
1378             my $private_caller = caller();
1379             if ( $private_caller ne __PACKAGE__ ) {
1380             die "cannot call private method penthos from $private_caller";
1381             }
1382             if ( defined $value ) {
1383             if ( ref $value || $value !~ m/^[-+\d]\d*$/ ) {
1384             die qq{Int: invalid value $value for accessor penthos};
1385             }
1386             $self->{penthos} = $value;
1387             }
1388             return $self->{penthos};
1389             }
1390              
1391             sub clear_penthos {
1392             my ($self) = @_;
1393             delete $self->{penthos};
1394             return $self;
1395             }
1396              
1397             sub has_penthos {
1398             my ($self) = @_;
1399             return exists $self->{penthos};
1400             }
1401              
1402             sub curae {
1403             my ( $self, $value ) = @_;
1404             my $private_caller = caller();
1405             if ( $private_caller ne __PACKAGE__ ) {
1406             die "cannot call private method curae from $private_caller";
1407             }
1408             if ( defined $value ) {
1409             if ( ref $value || $value !~ m/^[-+\d]\d*$/ ) {
1410             die qq{Int: invalid value $value for accessor curae};
1411             }
1412             $self->{curae} = $value;
1413             }
1414             return $self->{curae};
1415             }
1416              
1417             sub clear_curae {
1418             my ($self) = @_;
1419             delete $self->{curae};
1420             return $self;
1421             }
1422              
1423             sub has_curae {
1424             my ($self) = @_;
1425             return exists $self->{curae};
1426             }
1427              
1428             sub geras {
1429             my ( $self, $nosoi ) = @_;
1430             $nosoi = defined $nosoi ? $nosoi : 5;
1431             if ( !defined($nosoi) || ref $nosoi || $nosoi !~ m/^[-+\d]\d*$/ ) {
1432             $nosoi = defined $nosoi ? $nosoi : 'undef';
1433             die
1434             qq{Int: invalid value $nosoi for variable \$nosoi in method geras};
1435             }
1436             if ( $self->penthos == $nosoi ) { return $self->curae; }
1437             }
1438              
1439             1;
1440              
1441             __END__
1442              
1443             =head1 SUBROUTINES/METHODS
1444              
1445             =head2 run
1446              
1447             =over
1448              
1449             =item file
1450              
1451             Provide a file to read in.
1452              
1453             =item eval
1454              
1455             Provide a string to eval.
1456              
1457             =item verbose
1458              
1459             Set verbose to true, to print build steps to STDOUT.
1460              
1461             =item debug
1462              
1463             Set debug to true, to step through the build.
1464              
1465             =item dist
1466              
1467             Provide a name for the distribution.
1468              
1469             =item lib
1470              
1471             Provide a path where the generated files will be compiled.
1472              
1473             =item tlib
1474              
1475             Provide a path where the generates test files will be compiled.
1476              
1477             =item author
1478              
1479             The author of the distribution/module.
1480              
1481             =item email
1482              
1483             The authors email of the distribution/module.
1484              
1485             =item version
1486              
1487             The version number of the distribution/module.
1488              
1489             =item realm
1490              
1491             The Hades realm that is used to generate the code.
1492              
1493             =cut
1494              
1495             =back
1496              
1497             =head1 Hades
1498              
1499             =cut
1500              
1501             =head2 Class
1502              
1503             Declare a new class.
1504              
1505             Kosmos {
1506              
1507             }
1508              
1509             =cut
1510              
1511             =head3 Abstract
1512              
1513             Declare the classes Abstract.
1514              
1515             Kosmos {
1516             abstract { Afti einai i perilipsi }
1517             }
1518              
1519             =cut
1520              
1521             =head3 Synopsis
1522              
1523             Declare the classes Synopsis.
1524              
1525             Kosmos {
1526             synopsis {
1527             Schetika me ton Kosmos
1528              
1529             Kosmos->new;
1530             }
1531             }
1532              
1533             =cut
1534              
1535             =head3 Inheritance
1536              
1537             =cut
1538              
1539             =head4 base
1540              
1541             Establish an ISA relationship with base classes at compile time.
1542              
1543             Unless you are using the fields pragma, consider this discouraged in favor of the lighter-weight parent.
1544              
1545             Kosmos base Kato {
1546              
1547             }
1548              
1549             =cut
1550              
1551             =head4 parent
1552              
1553             Establish an ISA relationship with base classes at compile time.
1554              
1555             Kosmos parent Kato {
1556              
1557             }
1558              
1559             =cut
1560              
1561             =head4 require
1562              
1563             Require library files to be included if they have not already been included.
1564              
1565             Kosmos require Kato {
1566              
1567             }
1568              
1569             =cut
1570              
1571             =head4 use
1572              
1573             Declare modules that should be included in the class.
1574              
1575             Kosmos use Kato Vathys {
1576              
1577             }
1578              
1579             =cut
1580              
1581             =head3 Test
1582              
1583             Declare the classes additional tests.
1584              
1585             Kosmos {
1586             test {
1587             [
1588             ['ok', 'my $obj = Kosmos->new'],
1589             ['is', '$obj->dokimi', undef]
1590             ]
1591             }
1592             }
1593              
1594             =cut
1595              
1596             =head2 Compile phase
1597              
1598             =cut
1599              
1600             =head3 begin
1601              
1602             Define a code block is executed as soon as possible.
1603              
1604             Kosmos {
1605             begin {
1606             ... perl code ...
1607             }
1608             }
1609              
1610             =cut
1611              
1612             =head3 unitcheck
1613              
1614             Define a code block that is executed just after the unit which defined them has been compiled.
1615              
1616             Kosmos {
1617             unitcheck {
1618             ... perl code ...
1619             }
1620             }
1621              
1622             =cut
1623              
1624             =head3 check
1625              
1626             Define a code block that is executed just after the initial Perl compile phase ends and before the run time begins.
1627              
1628             Kosmos {
1629             check {
1630             ... perl code ...
1631             }
1632             }
1633              
1634             =cut
1635              
1636             =head3 init
1637              
1638             Define a code block that is executed just before the Perl runtime begins execution.
1639              
1640             Kosmos {
1641             init {
1642             ... perl code ...
1643             }
1644             }
1645              
1646             =cut
1647              
1648             =head3 end
1649              
1650             Define a code block is executed as late as possible.
1651              
1652             Kosmos {
1653             end {
1654             ... perl code ...
1655             }
1656             }
1657              
1658             =cut
1659              
1660             =head2 Variables
1661              
1662             =cut
1663              
1664             =head3 our
1665              
1666             Declare variable of the same name in the current package for use within the lexical scope.
1667              
1668             Kosmos {
1669             our $one %two
1670             }
1671              
1672             =cut
1673              
1674             =head2 Accessors
1675              
1676             Declare an accessor for the class
1677              
1678             Kosmos {
1679             dokimi
1680             dokimes
1681             }
1682              
1683             =cut
1684              
1685             =head3 :required | :r
1686              
1687             Making an accessor required means a value for the accessor must be supplied to the constructor.
1688              
1689             dokimi :r
1690             dokimes :required
1691              
1692             =cut
1693              
1694             =head3 :default | :d
1695              
1696             The default is used when no value for the accessor was supplied to the constructor.
1697              
1698             dokimi :d(Eimai o monos)
1699             dokimes :default([{ ola => "peripou", o => [qw/kosmos/] }])
1700              
1701             =cut
1702              
1703             =head3 :clearer | :c
1704              
1705             Setting clearer creates a method to clear the accessor.
1706              
1707             dokimi :c
1708             dokimes :clearer
1709              
1710             $class->clear_dokimi;
1711              
1712             =cut
1713              
1714             =head3 :coerce | :co
1715              
1716             Takes a coderef which is meant to coerce the attributes value.
1717              
1718             dokimi :co(array_to_string)
1719             dokimes :coerce($value = $value->[0] if ref($value) || "" eq "ARRAY";)
1720              
1721             =cut
1722              
1723             =head3 :private | :p
1724              
1725             Setting private makes the accessor only available to the class.
1726              
1727             dokimi :p
1728             dokimes :private
1729              
1730             =cut
1731              
1732             =head3 :predicate | :pr
1733              
1734             Takes a method name which will return true if an attribute has a value. The predicate is automatically named has_${accessor}.
1735              
1736             dokimi :pr
1737             dokimes :predicate
1738              
1739             =cut
1740              
1741             =head3 :trigger | :tr
1742              
1743             Takes a coderef which will get called any time the attribute is set.
1744              
1745             dokimi :tr(trigger_to_method)
1746             dokimes :trigger(warn Dumper $value)
1747              
1748             =cut
1749              
1750             =head3 :type | :t
1751              
1752             Add type checking to the accessor.
1753              
1754             dokimi :t(Dict[onoma => Str, id => Optional[Int], epiloges => Dict[onama => Str]])
1755             dokimes :type(Str)
1756              
1757             =cut
1758              
1759             =head3 :builder | :bdr
1760              
1761             Takes a coderef which is meant to build the attributes value.
1762              
1763             dokimi :bdr
1764             dokimes :builder($value = $value->[0] if ref($value) || "" eq "ARRAY";)
1765              
1766             =cut
1767              
1768             =head3 :test | :z
1769              
1770             Add tests associated to the accessor.
1771              
1772             dokimi :z(['ok', '$obj->dokimi'])
1773             dokimes :z(['deep', '$obj->dokimes({})', q|{}|)
1774              
1775             =cut
1776              
1777             =head2 Methods
1778              
1779             Declare a sub routine/method.
1780              
1781             Kosmos {
1782             dokimi {
1783             ... perl code ...
1784             }
1785             }
1786              
1787             =head3 Params
1788              
1789             Methods will always have $self defined but you can define additional params by declaring them before the code block.
1790              
1791             dokimi $one %two {
1792             ... perl code ...
1793             }
1794              
1795             generates
1796              
1797             sub dokimi {
1798             my ($self, $one, %two) = @_;
1799             ... perl code ...
1800             }
1801              
1802             =cut
1803              
1804             =head4 :type :t
1805              
1806             Add type checking to the param.
1807              
1808             dokimi $one :t(Str) {
1809             ... perl code ...
1810             }
1811              
1812             dokimes $one :t(Str) $two :t(HashRef) {
1813             ... perl code ...
1814             }
1815             =cut
1816              
1817             =head4 :coerce | :co
1818              
1819             Takes a coderef which is meant to coerce the method param.
1820              
1821             dokimi $str :co(array_to_string)
1822             dokimes $str :t(Str) :co(array_to_string)
1823              
1824             =cut
1825              
1826             =head3 :private :p
1827              
1828             Setting private makes the method only available to the class.
1829              
1830             dokimi :p {
1831             ... perl code ...
1832             }
1833             dokimes :private $one %two {
1834             ... perl code ...
1835             }
1836              
1837             =cut
1838              
1839             =head3 :default | :d
1840              
1841             The default is used when no value for the sub was passed as a param.
1842              
1843             dokimi $str :d(Eimai o monos) { }
1844             dokimes $arrayRef :default([{ ola => "peripou", o => [qw/kosmos/] }]) { }
1845              
1846             =cut
1847              
1848             =head3 :test | :z
1849              
1850             Add tests associated to the sub.
1851              
1852             dokimi :z(['ok', '$obj->dokimi']) { }
1853             dokimes :test(['deep', '$obj->dokimes({})', q|{}|) { }
1854              
1855             =cut
1856              
1857             =head3 :before | :b
1858              
1859             Before is called before the parent method is called. You can modify the params using the @params variable.
1860              
1861             dokimi :b {
1862             ... before ...
1863             }:
1864              
1865             generates
1866              
1867             sub dokimi {
1868             my ( $orig, $self, @params ) = ( 'SUPER::geras', @_ );
1869             ... before ...
1870             my @res = $self->$orig(@params);
1871             return @res;
1872             }
1873              
1874             =cut
1875              
1876             =head3 :around | :ar
1877              
1878             Around is called instead of the method it is modifying. The method you're overriding is passed in as the first argument (called $orig by convention). You can modify the params using the @params variable.
1879              
1880             dokimi :ar {
1881             ... before around ...
1882             my @res = $self->$orig(@params);
1883             ... after around ...
1884             }
1885              
1886             generates
1887              
1888             sub dokimi {
1889             my ( $orig, $self, @params ) = ( 'SUPER::geras', @_ );
1890             ... before around ...
1891             my @res = $self->$orig(@params);
1892             ... after around ...
1893             return @res;
1894             }
1895              
1896              
1897             =cut
1898              
1899             =head3 :after | :a
1900              
1901             After is called after the parent method is called. You can modify the response using the @res variable.
1902              
1903             dokimi :a {
1904             ... after ...
1905             }
1906              
1907             generates
1908              
1909             sub dokimi {
1910             my ( $orig, $self, @params ) = ( 'SUPER::geras', @_ );
1911             my @res = $self->$orig(@params);
1912             ... after ...
1913             return @res;
1914             }
1915              
1916             =cut
1917              
1918             =head2 Types
1919              
1920             =cut
1921              
1922             =head3 Any
1923              
1924             Absolutely any value passes this type constraint (even undef).
1925              
1926             dokimi :t(Any)
1927              
1928             =cut
1929              
1930             =head3 Item
1931              
1932             Essentially the same as Any. All other type constraints in this library inherit directly or indirectly from Item.
1933              
1934             dokimi :t(Item)
1935              
1936             =cut
1937              
1938             =head3 Bool
1939              
1940             Values that are reasonable booleans. Accepts 1, 0, the empty string and undef.
1941              
1942             dokimi :t(Bool)
1943              
1944             =cut
1945              
1946             =head3 Str
1947              
1948             Any string.
1949              
1950             dokimi :t(Str)
1951              
1952             =cut
1953              
1954             =head3 Num
1955              
1956             Any number.
1957              
1958             dokimi :t(Num)
1959              
1960             =cut
1961              
1962             =head3 Int
1963              
1964             An integer; that is a string of digits 0 to 9, optionally prefixed with a hyphen-minus character.
1965              
1966             dokimi :t(Int)
1967              
1968             =cut
1969              
1970             =head3 Ref
1971              
1972             Any defined reference value, including blessed objects.
1973              
1974             dokimi :t(Ref)
1975             dokimes :t(Ref[HASH])
1976              
1977             =cut
1978              
1979             =head3 ScalarRef
1980              
1981             A value where ref($value) eq "SCALAR" or ref($value) eq "REF".
1982              
1983             dokimi :t(ScalarRef)
1984             dokimes :t(ScalarRef[SCALAR])
1985              
1986             =cut
1987              
1988             =head3 ArrayRef
1989              
1990             A value where ref($value) eq "ARRAY".
1991              
1992             dokimi :t(ArrayRef)
1993             dokimes :t(ArrayRef[Str, 1, 100])
1994              
1995             =cut
1996              
1997             =head3 HashRef
1998              
1999             A value where ref($value) eq "HASH".
2000              
2001             dokimi :t(HashRef)
2002             dokimes :t(HashRef[Int])
2003              
2004             =cut
2005              
2006             =head3 CodeRef
2007              
2008             A value where ref($value) eq "CODE"
2009              
2010             dokimi :t(CodeRef)
2011              
2012             =cut
2013              
2014             =head3 RegexpRef
2015              
2016             A value where ref($value) eq "Regexp"
2017              
2018             dokimi :t(RegexpRef)
2019              
2020             =cut
2021              
2022             =head3 GlobRef
2023              
2024             A value where ref($value) eq "GLOB"
2025              
2026             dokimi :t(GlobRef)
2027              
2028             =cut
2029              
2030             =head3 Object
2031              
2032             A blessed object.
2033              
2034             dokimi :t(Object)
2035              
2036             =cut
2037              
2038             =head3 Map
2039              
2040             Similar to HashRef but parameterized with type constraints for both the key and value. The constraint for keys would typically be a subtype of Str.
2041              
2042             dokimi :t(Map[Str, Int])
2043              
2044             =cut
2045              
2046             =head3 Tuple
2047              
2048             Accepting a list of type constraints for each slot in the array.
2049              
2050             dokimi :t(Tuple[Str, Int, HashRef])
2051              
2052             =cut
2053              
2054             =head3 Dict
2055              
2056             Accepting a list of type constraints for each slot in the hash.
2057              
2058             dokimi :t(Dict[onoma => Str, id => Optional[Int], epiloges => Dict[onama => Str]])
2059              
2060             =cut
2061              
2062             =head3 Optional
2063              
2064             Used in conjunction with Dict and Tuple to specify slots that are optional and may be omitted.
2065              
2066             dokimi :t(Optional[Str])
2067              
2068             =cut
2069              
2070             =head2 Macros
2071              
2072             Hades has a concept of macros that allow you to write re-usable code. see L<https://metacpan.org/source/LNATION/Hades-0.26/macro-fh.hades> for an example of how to extend via macros.
2073              
2074             macro {
2075             FH [ macro => [qw/read_file write_file/], alias => { read_file => [qw/rf/], write_file => [qw/wf/] } ]
2076             str2ArrayRef :a(s2ar) {
2077             return qq|$params[0] = [ $params[0] ];|;
2078             }
2079             ArrayRef2Str :a(ar2s) {
2080             return qq|$params[0] = $params[0]\->[0];|;
2081             }
2082             }
2083             MacroKosmos {
2084             eros $eros :t(Str) :d(t/test.txt) {
2085             €s2ar('$eros');
2086             €ar2s('$eros');
2087             €wf('$eros', q|'this is a test'|);
2088             return $eros;
2089             }
2090             psyche $psyche :t(Str) :d(t/test.txt) {
2091             €rf('$psyche');
2092             return $content;
2093             }
2094             }
2095              
2096             ... generates ...
2097              
2098             package MacroKosmos;
2099             use strict;
2100             use warnings;
2101             our $VERSION = 0.01;
2102              
2103             sub new {
2104             my ( $cls, %args ) = ( shift(), scalar @_ == 1 ? %{ $_[0] } : @_ );
2105             my $self = bless {}, $cls;
2106             my %accessors = ();
2107             for my $accessor ( keys %accessors ) {
2108             my $value
2109             = $self->$accessor(
2110             defined $args{$accessor}
2111             ? $args{$accessor}
2112             : $accessors{$accessor}->{default} );
2113             unless ( !$accessors{$accessor}->{required} || defined $value ) {
2114             die "$accessor accessor is required";
2115             }
2116             }
2117             return $self;
2118             }
2119              
2120             sub eros {
2121             my ( $self, $eros ) = @_;
2122             $eros = defined $eros ? $eros : "t/test.txt";
2123             if ( !defined($eros) || ref $eros ) {
2124             $eros = defined $eros ? $eros : 'undef';
2125             die qq{Str: invalid value $eros for variable \$eros in method eros};
2126             }
2127              
2128             $eros = [$eros];
2129             $eros = $eros->[0];
2130             open my $wh, ">", $eros or die "cannot open file for writing: $!";
2131             print $wh 'this is a test';
2132             close $wh;
2133             return $eros;
2134              
2135             }
2136              
2137             sub psyche {
2138             my ( $self, $psyche ) = @_;
2139             $psyche = defined $psyche ? $psyche : "t/test.txt";
2140             if ( !defined($psyche) || ref $psyche ) {
2141             $psyche = defined $psyche ? $psyche : 'undef';
2142             die
2143             qq{Str: invalid value $psyche for variable \$psyche in method psyche};
2144             }
2145              
2146             open my $fh, "<", $psyche or die "cannot open file for reading: $!";
2147             my $content = do { local $/; <$fh> };
2148             close $fh;
2149             return $content;
2150             }
2151              
2152             1;
2153              
2154             __END__
2155              
2156             =head2 Testing
2157              
2158             Hades can auto-generate test files. If you take the following example:
2159              
2160             use Hades;
2161             Hades->run({
2162             eval => q|Dokimes {
2163             curae :r :default(5)
2164             penthos :t(Str) :r
2165             nosoi :default(3) :t(Int) :clearer
2166             limos
2167             $test :t(Str)
2168             :test(
2169             ['ok', '$obj->penthos(2) && $obj->nosoi(2) && $obj->curae(5)'],
2170             ['is', '$obj->limos("yay")', 5 ],
2171             ['ok', '$obj->penthos(5)' ],
2172             ['is', '$obj->limos("yay")', q{''}]
2173             )
2174             { if ($_[0]->penthos == $_[0]->nosoi) { return $_[0]->curae; } }
2175             }|,
2176             lib => 'lib',
2177             tlib => 't/lib',
2178             });
2179              
2180              
2181             It will generate a test file located at t/lib/Dokimes.t which looks like:
2182              
2183             use Test::More;
2184             use strict;
2185             use warnings;
2186             BEGIN { use_ok('Dokimes'); }
2187             subtest 'new' => sub {
2188             plan tests => 16;
2189             ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ),
2190             q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})}
2191             );
2192             ok( $obj = Dokimes->new( curae => 'hypnos', penthos => 'aporia' ),
2193             q{$obj = Dokimes->new(curae => 'hypnos', penthos => 'aporia')}
2194             );
2195             isa_ok( $obj, 'Dokimes' );
2196             ok( $obj = Dokimes->new( { penthos => 'aporia', nosoi => 10 } ),
2197             q{$obj = Dokimes->new({penthos => 'aporia', nosoi => 10})}
2198             );
2199             ok( $obj = Dokimes->new( penthos => 'aporia', nosoi => 10 ),
2200             q{$obj = Dokimes->new(penthos => 'aporia', nosoi => 10)}
2201             );
2202             is( $obj->curae, 5, q{$obj->curae} );
2203             ok( $obj = Dokimes->new(
2204             { curae => 'hypnos', penthos => 'aporia', nosoi => 10 }
2205             ),
2206             q{$obj = Dokimes->new({ curae => 'hypnos', penthos => 'aporia', nosoi => 10 })}
2207             );
2208             eval { $obj = Dokimes->new( { curae => 'hypnos', nosoi => 10 } ) };
2209             like( $@, qr/required/,
2210             q{$obj = Dokimes->new({curae => 'hypnos', nosoi => 10})} );
2211             eval {
2212             $obj = Dokimes->new(
2213             { curae => 'hypnos', penthos => [], nosoi => 10 } );
2214             };
2215             like(
2216             $@,
2217             qr/invalid value|greater|atleast/,
2218             q{$obj = Dokimes->new({ curae => 'hypnos', penthos => [], nosoi => 10 })}
2219             );
2220             eval {
2221             $obj = Dokimes->new(
2222             { curae => 'hypnos', penthos => \1, nosoi => 10 } );
2223             };
2224             like(
2225             $@,
2226             qr/invalid value|greater|atleast/,
2227             q{$obj = Dokimes->new({ curae => 'hypnos', penthos => \1, nosoi => 10 })}
2228             );
2229             eval {
2230             $obj = Dokimes->new(
2231             { curae => 'hypnos', penthos => '', nosoi => 10 } );
2232             };
2233             like(
2234             $@,
2235             qr/invalid value|greater|atleast/,
2236             q{$obj = Dokimes->new({ curae => 'hypnos', penthos => '', nosoi => 10 })}
2237             );
2238             ok( $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ),
2239             q{$obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})}
2240             );
2241             ok( $obj = Dokimes->new( curae => 'hypnos', penthos => 'aporia' ),
2242             q{$obj = Dokimes->new(curae => 'hypnos', penthos => 'aporia')}
2243             );
2244             is( $obj->nosoi, 3, q{$obj->nosoi} );
2245             eval {
2246             $obj = Dokimes->new(
2247             { curae => 'hypnos', penthos => 'aporia', nosoi => [] } );
2248             };
2249             like(
2250             $@,
2251             qr/invalid value|greater|atleast/,
2252             q{$obj = Dokimes->new({ curae => 'hypnos', penthos => 'aporia', nosoi => [] })}
2253             );
2254             eval {
2255             $obj = Dokimes->new(
2256             { curae => 'hypnos', penthos => 'aporia', nosoi => 'limos' } );
2257             };
2258             like(
2259             $@,
2260             qr/invalid value|greater|atleast/,
2261             q{$obj = Dokimes->new({ curae => 'hypnos', penthos => 'aporia', nosoi => 'limos' })}
2262             );
2263             };
2264             subtest 'curae' => sub {
2265             plan tests => 2;
2266             ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ),
2267             q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})}
2268             );
2269             can_ok( $obj, 'curae' );
2270             };
2271             subtest 'penthos' => sub {
2272             plan tests => 7;
2273             ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ),
2274             q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})}
2275             );
2276             can_ok( $obj, 'penthos' );
2277             is_deeply( $obj->penthos('curae'), 'curae', q{$obj->penthos('curae')} );
2278             eval { $obj->penthos( [] ) };
2279             like( $@, qr/invalid value|greater|atleast/, q{$obj->penthos([])} );
2280             eval { $obj->penthos( \1 ) };
2281             like( $@, qr/invalid value|greater|atleast/, q{$obj->penthos(\1)} );
2282             eval { $obj->penthos('') };
2283             like( $@, qr/invalid value|greater|atleast/, q{$obj->penthos('')} );
2284             is_deeply( $obj->penthos, 'curae', q{$obj->penthos} );
2285             };
2286             subtest 'nosoi' => sub {
2287             plan tests => 6;
2288             ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ),
2289             q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})}
2290             );
2291             can_ok( $obj, 'nosoi' );
2292             is_deeply( $obj->nosoi(10), 10, q{$obj->nosoi(10)} );
2293             eval { $obj->nosoi( [] ) };
2294             like( $@, qr/invalid value|greater|atleast/, q{$obj->nosoi([])} );
2295             eval { $obj->nosoi('phobos') };
2296             like( $@, qr/invalid value|greater|atleast/, q{$obj->nosoi('phobos')} );
2297             is_deeply( $obj->nosoi, 10, q{$obj->nosoi} );
2298             };
2299             subtest 'limos' => sub {
2300             plan tests => 10;
2301             ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ),
2302             q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})}
2303             );
2304             can_ok( $obj, 'limos' );
2305             eval { $obj->limos( [] ) };
2306             like( $@, qr/invalid value|greater|atleast/, q{$obj->limos([])} );
2307             eval { $obj->limos( \1 ) };
2308             like( $@, qr/invalid value|greater|atleast/, q{$obj->limos(\1)} );
2309             eval { $obj->limos('') };
2310             like( $@, qr/invalid value|greater|atleast/, q{$obj->limos('')} );
2311             eval { $obj->limos(undef) };
2312             like( $@, qr/invalid value|greater|atleast/, q{$obj->limos(undef)} );
2313             ok( $obj->penthos(2) && $obj->nosoi(2) && $obj->curae(5),
2314             q{$obj->penthos(2) && $obj->nosoi(2) && $obj->curae(5)}
2315             );
2316             is( $obj->limos("yay"), 5, q{$obj->limos("yay")} );
2317             ok( $obj->penthos(5), q{$obj->penthos(5)} );
2318             is( $obj->limos("yay"), '', q{$obj->limos("yay")} );
2319             };
2320             subtest 'clear_nosoi' => sub {
2321             plan tests => 5;
2322             ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ),
2323             q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})}
2324             );
2325             can_ok( $obj, 'clear_nosoi' );
2326             is_deeply( $obj->nosoi(10), 10, q{$obj->nosoi(10)} );
2327             ok( $obj->clear_nosoi, q{$obj->clear_nosoi} );
2328             is( $obj->nosoi, undef, q{$obj->nosoi} );
2329             };
2330             done_testing();
2331              
2332              
2333             and has 100% test coverage.
2334              
2335             cover --test
2336              
2337             ------------------- ------ ------ ------ ------ ------ ------
2338             File stmt bran cond sub time total
2339             ------------------- ------ ------ ------ ------ ------ ------
2340             blib/lib/Dokimes.pm 100.0 100.0 100.0 100.0 100.0 100.0
2341             Total 100.0 100.0 100.0 100.0 100.0 100.0
2342             ------------------- ------ ------ ------ ------ ------ ------
2343              
2344             =cut
2345              
2346             =head3 tests
2347              
2348             Unfortunately not all code can have auto generated tests, so you should use the :test attribute to define additional
2349             to test custom logic.
2350              
2351             =cut
2352              
2353             =head4 ok
2354              
2355             This simply evaluates any expression ($got eq $expected is just a simple example) and uses that to determine if the test succeeded or failed. A true expression passes, a false one fails.
2356              
2357             ['ok', '$obj->$method']
2358              
2359             =cut
2360              
2361             =head4 can_ok
2362              
2363             Checks to make sure the $module or $object can do these @methods (works with functions, too).
2364              
2365             ['can_ok', '$obj', $method]
2366              
2367             =cut
2368              
2369             =head4 isa_ok
2370              
2371             Checks to see if the given $object->isa($class). Also checks to make sure the object was defined in the first place. Handy for this sort of thing:
2372              
2373             ['isa_ok', '$obj', $class]
2374              
2375             =cut
2376              
2377             =head4 is
2378              
2379             Similar to ok(), is() and isnt() compare their two arguments with eq and ne respectively and use the result of that to determine if the test succeeded or failed. So these:
2380              
2381             ['is', '$obj->$method', $expected]
2382              
2383             =cut
2384              
2385             =head4 isnt
2386              
2387             ['isnt', '$obj->$method', $expected]
2388              
2389             =cut
2390              
2391             =head4 like
2392              
2393             Similar to ok(), like() matches $got against the regex qr/expected/.
2394              
2395             ['like', '$obj->$method', $expected_regex]
2396              
2397             =cut
2398              
2399             =head4 unlike
2400              
2401             Works exactly as like(), only it checks if $got does not match the given pattern.
2402              
2403             ['unlike', '$obj->$method', $expected_regex]
2404              
2405             =cut
2406              
2407             =head4 deep
2408              
2409             Similar to is(), except that if $got and $expected are references, it does a deep comparison walking each data structure to see if they are equivalent. If the two structures are different, it will display the place where they start differing.
2410              
2411             ['deep', '$obj->$method', $expected]
2412              
2413             =cut
2414              
2415             =head4 eval
2416              
2417             Evaluate code that you expect to die and check the warning using like.
2418              
2419             ['eval', '$obj->$method", $error_expected]
2420              
2421             =cut
2422              
2423             =head1 AUTHOR
2424              
2425             LNATION, C<< <email at lnation.org> >>
2426              
2427             =head1 BUGS
2428              
2429             Please report any bugs or feature requests to C<bug-hades at rt.cpan.org>, or through
2430             the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Hades>. I will be notified, and then you'll
2431             automatically be notified of progress on your bug as I make changes.
2432              
2433             =head1 SUPPORT
2434              
2435             You can find documentation for this module with the perldoc command.
2436              
2437             perldoc Hades
2438              
2439             You can also look for information at:
2440              
2441             =over 4
2442              
2443             =item * RT: CPAN's request tracker (report bugs here)
2444              
2445             L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=Hades>
2446              
2447             =item * Search CPAN
2448              
2449             L<https://metacpan.org/release/Hades>
2450              
2451             =back
2452              
2453             =head1 ACKNOWLEDGEMENTS
2454              
2455             =head1 LICENSE AND COPYRIGHT
2456              
2457             This software is Copyright (c) 2020->2025 by LNATION.
2458              
2459             This is free software, licensed under:
2460              
2461             The Artistic License 2.0 (GPL Compatible)
2462              
2463              
2464             =cut
2465              
2466             1; # End of Hades