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