File Coverage

blib/lib/Hades.pm
Criterion Covered Total %
statement 653 721 90.5
branch 206 268 76.8
condition 75 98 76.5
subroutine 93 119 78.1
pod 3 44 6.8
total 1030 1250 82.4


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