File Coverage

blib/lib/Fukurama/Class.pm
Criterion Covered Total %
statement 91 117 77.7
branch 30 44 68.1
condition 6 6 100.0
subroutine 17 18 94.4
pod 2 2 100.0
total 146 187 78.0


line stmt bran cond sub pod time code
1             package Fukurama::Class;
2 3     3   102000 use 5.008;
  3         11  
  3         153  
3 3     3   1593 use Fukurama::Class::Rigid;
  3         8  
  3         19  
4 3     3   20 use Fukurama::Class::Carp;
  3         5  
  3         15  
5 3     3   1711 use Fukurama::Class::Version();
  3         9  
  3         149  
6             our $VERSION;
7             BEGIN {
8 3     3   8 $VERSION = 0.032;
9 3         18 Fukurama::Class::Version->import($VERSION);
10             }
11 3     3   1923 use Fukurama::Class::Extends();
  3         8  
  3         67  
12 3     3   1847 use Fukurama::Class::Implements();
  3         9  
  3         60  
13 3     3   1873 use Fukurama::Class::Abstract();
  3         9  
  3         76  
14 3     3   1725 use Fukurama::Class::Attributes();
  3         11  
  3         67  
15 3     3   20 use Fukurama::Class::Version();
  3         212  
  3         52  
16 3     3   17 use Fukurama::Class::DataTypes();
  3         4  
  3         42  
17 3     3   19 use Data::Dumper();
  3         4  
  3         3896  
18              
19             my $ALLOWED = {
20             extends => ['', 'class'],
21             implements => ['[]', 'class'],
22             abstract => ['', 'boolean'],
23             version => ['', 'decimal'],
24             };
25             my $CHECK_OPTIONS = {
26             '' => 0,
27             checks => 0,
28             runtime_checks => 1,
29             };
30             my $DISABLE_ALL = 0;
31             my $ONLY_CHECK_COMPILETIME = 1;
32              
33             # AUTOMAGIC void
34             sub import {
35 25     25   10245 my $class = shift(@_);
36 25         67 my @options = @_;
37            
38 25         94 my ($caller) = caller(0);
39 25         81 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
40 25         89 $class->declare($caller, 1, @options);
41 19         888 return undef;
42             }
43             # AUTOMAGIC void
44             sub unimport {
45 0     0   0 my $class = $_[0];
46 0         0 my $check_level = $_[1];
47 0 0       0 $check_level = '' if(!defined($check_level));
48            
49 0         0 my $level = $CHECK_OPTIONS->{$check_level};
50 0 0       0 _croak("Error in configuration: option 'no $class($check_level)' is not allowed.") if(!defined($level));
51            
52 0 0       0 if($level > $ONLY_CHECK_COMPILETIME) {
53 0         0 $Fukurama::Class::Extends::CHECK_LEVEL = $Fukurama::Class::Extends::LEVEL_CHECK_CHILDS;
54 0         0 $Fukurama::Class::Implements::CHECK_LEVEL = $Fukurama::Class::Implements::LEVEL_CHECK_ALL;
55 0         0 $Fukurama::Class::Attributes::CHECK_LEVEL = $Fukurama::Class::Attributes::LEVEL_CHECK_ALL;
56 0         0 $Fukurama::Class::Attributes::OOStandard::CHECK_LEVEL = $Fukurama::Class::Attributes::OOStandard::LEVEL_CHECK_ALL;
57             }
58            
59 0 0       0 if($level <= $ONLY_CHECK_COMPILETIME) {
60 0         0 $Fukurama::Class::Abstract::DISABLE = 1;
61 0         0 $Fukurama::Class::Attributes::OOStandard::DISABLE_RUNTIME_CHECK = 1;
62             }
63            
64 0 0       0 if($level <= $DISABLE_ALL) {
65 0         0 $Fukurama::Class::Extends::CHECK_LEVEL = $Fukurama::Class::Extends::LEVEL_DISABLE;
66 0         0 $Fukurama::Class::Implements::CHECK_LEVEL = $Fukurama::Class::Implements::LEVEL_CHECK_NONE;
67 0         0 $Fukurama::Class::Attributes::CHECK_LEVEL = $Fukurama::Class::Attributes::LEVEL_CHECK_NONE;
68 0         0 $Fukurama::Class::Attributes::OOStandard::CHECK_LEVEL = $Fukurama::Class::Attributes::OOStandard::LEVEL_CHECK_NONE;
69 0         0 $Fukurama::Class::HideCaller::DISABLE = 1;
70 0         0 $Fukurama::Class::Rigid::DISABLE = 1;
71             }
72 0         0 return;
73             }
74             # STATIC void
75             sub declare {
76 25     25 1 45 my $class = shift(@_);
77 25         32 my $declare_class = shift(@_);
78 25         35 my $import_depth = shift(@_);
79 25         50 my @options = @_;
80            
81 25 100       80 _croak('Error in class definition syntax. Uneven count of parameters given.') if(@options % 2);
82 24         120 Fukurama::Class::Attributes->register_class($declare_class);
83 24         135 Fukurama::Class::Rigid->rigid($import_depth + 1);
84            
85 24         74 my $options = { @options };
86 24 100       103 if(scalar(@options) != (scalar(keys(%$options)) * 2) ) {
87 1         5 _croak('Error in class definition syntax. Some options are defined twice.');
88             }
89            
90 23         58 foreach my $option (keys(%$options)) {
91 22         50 my $def = $ALLOWED->{$option};
92 22 100       63 _croak("Error in class definition syntax. Option '$option' is not allowed.") if(!$def);
93 21         30 my $value = $options->{$option};
94 21         71 $class->_check_option($declare_class, $option, $value, $def);
95 18         56 $class->_handle_option($declare_class, $option, $value);
96             }
97 19         74 return;
98             }
99             # STATIC void
100             sub _check_option {
101 21     21   30 my $class = $_[0];
102 21         31 my $declare_class = $_[1];
103 21         30 my $option = $_[2];
104 21         33 my $value = $_[3];
105 21         26 my $def = $_[4];
106            
107 21         37 my $ref = $def->[0];
108 21 100 100     82 $ref = '' if($option eq 'implements' && ref($value) ne 'ARRAY');
109            
110 21         108 my $check = Fukurama::Class::DataTypes->get_check_definition($def->[1], $ref);
111 21         46 my ($ok, $evaluated_value, $value_failure) = &{$check->{'check'}}($check->{'param_0'}, $value);
  21         83  
112            
113 21 100 100     106 $ok = 1 if($option eq 'extends' && $value eq '');
114            
115 21 100       48 my $error = ($value_failure ? " ($value_failure)" : '');
116 21 100       54 if($check->{'is_class'}) {
117 16         30 $error .= " Maybe the class doesn't exist or isn't loaded.";
118             }
119 21 100       52 $evaluated_value = join(', ', @$evaluated_value) if(ref($evaluated_value) eq 'ARRAY');
120 21 50       45 if(ref($evaluated_value) eq 'HASH') {
121 0         0 $evaluated_value = Data::Dumper::Dumper($evaluated_value);
122 0         0 $evaluated_value =~ s/^\$VAR1 = //;
123 0         0 $evaluated_value =~ s/;\n$//;
124             }
125 21 100       43 if(!$ok) {
126 3 50       8 $evaluated_value = '' if(!defined($evaluated_value));
127 3         21 _croak("Error in class definition syntax. Value '$evaluated_value' for option '$option' is not allowed. $error");
128             }
129 18         64 return;
130             }
131             # STATIC void
132             sub _handle_option {
133 18     18   33 my $class = $_[0];
134 18         23 my $declare_class = $_[1];
135 18         23 my $option = $_[2];
136 18         28 my $value= $_[3];
137            
138 18 100       69 if($option eq 'extends') {
    100          
    100          
    50          
139 10         60 Fukurama::Class::Extends->extends($declare_class, $value);
140              
141             } elsif($option eq 'version') {
142 2         18 Fukurama::Class::Version->version($declare_class, $value);
143              
144             } elsif($option eq 'implements') {
145 4 100       13 foreach my $interface ((ref($value) eq 'ARRAY' ? @$value : $value)) {
146 4         18 Fukurama::Class::Implements->implements($declare_class, $interface);
147             }
148              
149             } elsif($option eq 'abstract') {
150 2 50       27 Fukurama::Class::Abstract->abstract($declare_class) if($value);
151             }
152 18         78 return;
153             }
154             # STATIC void
155             sub run_check {
156 2     2 1 18 Fukurama::Class::Extends->run_check();
157 2         11 Fukurama::Class::Implements->run_check();
158 0           Fukurama::Class::Abstract->run_check();
159 0           Fukurama::Class::Attributes->run_check();
160             }
161              
162             =head1 NAME
163              
164             Fukurama::Class - Pragma to extend the Perl-OO (in native Perl)
165              
166             =head1 VERSION
167              
168             Version 0.032 (beta)
169              
170             =head1 SYNOPSIS
171              
172             package MyClass;
173             use Fukurama::Class(
174             extends => 'MyParent::Class',
175             implements => ['MyFirst::Interface', 'MySecond::Interface'],
176             abstract => 1,
177             version => 1.7,
178             );
179             sub new : Constructor(public|string) {
180             my $class = $_[0];
181             my $name = $_[1];
182            
183             bless({ name => $name }, $class);
184             }
185             sub get_name : Method(public final|string|) {
186             my $self = $_[0];
187            
188             return $self->{'name'};
189             }
190             1;
191              
192              
193             =head1 EXPORT
194              
195             =head2 METHODS
196              
197             I, I, I
198              
199             Existing ones will be decorated, not overwritten
200              
201             =head2 CODE ATTRIBUTES
202              
203             I, I
204              
205             =head1 CHANGES OF PERL MODULES
206              
207             =head2 UNIVERSAL::isa
208              
209             This method would be decorated to handle the implemented interfaces.
210              
211             =head2 CORE::GLOBAL::caller
212              
213             This method would be decorated to hide the check-wrappers for I and I attributes.
214              
215             =head1 PROVIDED FUNCTIONS
216              
217             =over 4
218              
219             =item use of strict and warnings by default
220              
221             I and I are activated by default in your class.
222              
223             =item package-name check
224              
225             Your packagename has to be as provided by path and filename to avoid typos.
226              
227             =item Abstract classes
228              
229             Any access to these classes from non-childs would croak at B
230              
231             =item Multi-inheritation check
232              
233             Multiple defined methods in multi-inheritations would croak at B
234              
235             =item Implementation of interfaces
236              
237             Not implemented subs would croak at B
238              
239             =item Constructor and method signatures
240              
241             Non-static subs croak at B if you call them as static sub
242              
243             Private subs croak at B if you call them from other classes
244              
245             Protected subs croak at B if you call them from outside the inheritation
246              
247             Final subs croak at B if any child try to overwrite them
248              
249             Abstract methods croak at B if you doesn't define them in the child class
250              
251             Abstract methods croak at B if you call them
252              
253             =item Parameter and return-value check of methods and constructors
254              
255             Any parameter which isn't equivalent to the signature would croak at B
256              
257             Any return value which isn't equivalent to the signature would croak at B
258              
259             =back
260              
261             =head1 DESCRIPTION
262              
263             Use this pragma to have more reliability for developing your programs. It will slow down your code a bit but you
264             can disable the whole pragma for production with only one line without any side effect.
265              
266             =head2 PRAGMA-OPTIONS
267              
268             =over 4
269              
270             =item B => STRING
271              
272             Define, from wich class you would inherit. This is only a wrapper for the B pragma. Feel free to use this
273             one or B direct. It's only for the sake of completeness.
274              
275             =item B => ARRAYREF of STRING
276              
277             A list of interfaces you have to implement. You will not inherit from theese classes even thought UNIVERSAL::isa
278             will say that.
279              
280             =item B => BOOLEAN
281              
282             Declare this class as an abstract one.
283              
284             =item B => INT
285              
286             Set the $VERSION variable in your module. Same as you say B (at B)
287              
288             =back
289              
290             =head2 DEFINE SIGNATURES
291              
292             You can define signatures for constructors and methods. If you overwride some subs from your parent-class, you have
293             to use exact the same signature ore an extended version (see L). Otherwise it will croak
294             at B.
295              
296             =over 4
297              
298             =item Constructor signatures
299              
300             sub new : Constructor(ACCESS_LEVEL TYPE | PARAMETERS) {
301              
302             Any constructor is static. But if you call $object->new( ) it will cause no check-error.
303              
304             The return-value of any constructor has to be a blessed reference which is a member of the actual class.
305              
306             =item Method signatures
307              
308             sub get : Method(ACCESS_LEVEL IS_STATIC TYPE | RETURN_VALUE | PARAMETERS) {
309              
310             =back
311              
312             =head3 DECLARATION OPTIONS
313              
314             =over 4
315              
316             =item B: ENUM
317              
318             Can be on of the following. If you overwrite methods, you can't change the access-level in the
319             inheritation tree, because public methods start with no underscore and all other with an underscore.
320             With this caveat and the fact, that there are no real private methods in perl it's more uncomplicated
321             to do so.
322              
323             =over 4
324              
325             =item I
326              
327             You can access these sub from anywhere. There are no restrictions.
328              
329             =item I
330              
331             You can access these sub only from its own package or members of this class (even parents). All calls from
332             outside will croak at B.
333              
334             =item I
335              
336             You can access these sub only from its own package. All other calls will croak at B.
337              
338             =back
339              
340             There are two things to comply the perl-styleguide:
341              
342             =over 4
343              
344             =item sub _methodname
345              
346             Any sub with an I can be protected or private. If you doesn't define the ACCESS_LEVEL,
347             it will be protected by default. If you define this as public it will croak at B.
348              
349             =item sub methodname
350              
351             Any sub with no initial unterscore can be only public. If you doesn't define the ACCESS_LEVEL, it will be
352             public by default. If you define it as protected or private it will croak at B
353              
354             =back
355              
356             so you can say:
357              
358             sub _methodname : Method(|void|)
359              
360             and you will get the same as
361              
362             sub _methodname : Method(protected|void|)
363              
364             =item B: ENUM
365              
366             Can be...
367              
368             =over 4
369              
370             =item I
371              
372             If the sub is static, you can call it direct via CLASSNAME->sub( ) or via object $obj->sub(). A direct call
373             via I<&sub()> will croak at B.
374              
375             =back
376              
377             If static is not defined, you can only call these sub via $object->sub(). All other accesses will croak
378             at B
379              
380             =item B: ENUM
381              
382             Can be one of...
383              
384             =over 4
385              
386             =item B
387              
388             This sub is abstract. You doesn't have to define any method-body, because this method could be never called.
389             All children of this class have to implement this method with the same or the extended method-signature.
390              
391             =item B
392              
393             This sub is finalized. No child can overwrite an redifine this method. This will croak at B
394              
395             =back
396              
397             =item B
398              
399             The definition of the return value. In this standard definition there is no determination between array and
400             scalar context. If you define void as return value and call it in scalar or array context, there would be
401             no warning.
402              
403             If there is a difference between array and scalar context, you have to define the array-context return values
404             separate after an @ like
405              
406             sub append : Method(public|SCALAR_RETURN @ ARRAY_RETURN|);
407              
408             B
409              
410             =over 4
411              
412             =item sub append : Method( public|string| )
413              
414             returns a string
415            
416             =item sub append : Method( public|string, boolean| )
417              
418             returns a string and a boolean
419            
420             =item sub append : Method( public|string[] @ string()| )
421              
422             returns an arrayref of strings in scalar, and an array of strings in array context
423              
424             =back
425              
426             =item B
427              
428             The definition, which parameters your sub can take seperated by comma. If there is no parameter you have
429             to define nothing.
430              
431             Optional parameters can be defined after a semicolon.
432              
433             B
434              
435             =over 4
436              
437             =item sub append : Method( public|void| )
438              
439             Takes no parameters
440              
441             =item sub append : Method( public|void|string )
442              
443             Takes a single string as parameter
444              
445             =item sub append : Method( public | void | string[]; scalar, scalar )
446              
447             Takes an arrayref of strings and two optional scalars as parameters
448              
449             =back
450              
451             =back
452              
453             =head3 POSSIBLE PARAMETERS AND RETURN VALUES
454              
455             The following things you can use for parameters or return values:
456              
457             =over 4
458              
459             =item void (only for return values)
460              
461             The sub returns nothing (undef). Only valid for a single return value.
462              
463             It isn't valid if you try to define a void return value for array-context or any other return value with void.
464             This will croak at B
465              
466             =item scalar
467              
468             Anything what you can put into a scalar variable, i.e. references, strings, objects, undef, etc.
469              
470             =item scalarref
471              
472             A reference to a scalar.
473              
474             =item arrayref
475              
476             A reference to an array.
477              
478             =item hashref
479              
480             A reference to a hash.
481              
482             =item typeglobref
483              
484             A reference to a typeglob
485              
486             =item string
487              
488             A scalar with string content. It behaves like scalar but it can't be undef.
489              
490             =item boolean
491              
492             A scalar which can contain 1 or 0.
493              
494             =item int
495              
496             A scalar which can contain an integer. It can't be undef. If this number is too big and produced
497             an overflow, for exampe a string with a huge number, it will croak at B.
498              
499             =item float
500              
501             A scalar which can contain any floatingpoint number. It can't be undef. If the number is too big
502             and produced an overflow it will croak at B like in int.
503              
504             =item decimal
505              
506             A scalar which can contain any decimal number. It can't be undef. If the number is too big and
507             produced an overflow it will croak at B like in int.
508              
509             B
510              
511             If you use too many digits after the point like 1.000000000000001, perl will cut this down to "1"
512             without any notice if you use it as number direct in your code or if you calculate with it. If you
513             give such a number to a method as string, Fukurama::Class would find fault with "overflow".
514              
515             =item class
516              
517             A string which contain a valid classname, i.e 'UNIVERSAL'. Can't be undef.
518              
519             =item object
520              
521             A scalar which can contain any object.
522              
523             =item AnyClassname
524              
525             If there is no specific declaration for the datatype this would be interpreted as class. The parameter or return
526             value must be an OBJECT and a member of the defined class.
527              
528             =back
529              
530             At each of these things you can add trailing [] or () to say, that this is an arrayref or an array
531             or these thing. The () can be used for array-context return values and then it has
532             to be the last or the only return value. It also can be the last parameter/optional parameter.
533              
534             B: you can never add some parameters or return values when you use it!
535              
536             Example:
537              
538             =over 4
539              
540             =item int[]
541              
542             An arrayref that contain only integers
543              
544             =item MyClass( )
545              
546             An array that contain only members of the MyClass-class.
547              
548             =back
549              
550             =head2 EXTEND SIGNATURES
551              
552             You can extend signatures by the following ways:
553              
554             =over 4
555              
556             =item set final
557              
558             Any Non-final sub can be declared as final to avoid overwriting.
559              
560             =item add new, optional parameter
561              
562             You can add (more) optional parameters. The even defined parameters from the sub you overwrite must
563             be exact the same. To overwrite and extend a method for the example parent:
564              
565             package Parent;
566             sub get_name : Method(public|string|boolean) {
567              
568             ...you can say:
569              
570             package Child;
571             sub get_name : Method(public|string|boolean;string) {
572              
573             ...but not:
574              
575             package Child;
576             sub get_name : Method(public|string|string) {
577              
578             this will croak at B
579              
580             =back
581              
582             =head1 LOAD CLASSES AT RUNTIME
583              
584             If some classes are loaded at runtime there couldn't be checked at compiletime. So these classes are
585             checked at destroy-time (END-block) and you will become a warning about this at runtime when the class is loaded.
586              
587             =head1 DISABLE ALL CHECKS
588              
589             To speed up your code to use it productive you can say:
590              
591             =over 4
592              
593             =item no Fukurama::Class('runtime_checks');
594              
595             This will disable all runtime checks as to callers, parameters and return values. This will speed up
596             your code most.
597              
598             =item no Fukurama::Class('checks');
599              
600             This will disable all checks for runtime as above and for compiletime as to checks of implementations
601             of abstract methods and interfaces, use same or extended signatures for overwritten subs and the package-name checks.
602              
603             If you say this, only decorations for the methods B and B
604             (which will be in several classes) would stay. Even B are disabled, because of the runtime-warning checks.
605              
606             But the B would never be disabled.
607              
608             =back
609              
610             =head1 CUSTOM SETTINGS
611              
612             You can control the whole behavior of all submodules. Take a look at the specific module documentation.
613              
614             =head1 METHODS
615              
616             =over 4
617              
618             =item declare( export_to_class:STRING, export_depth:INT ) return:VOID
619              
620             Helper method to white wrapper or adapter for this class. You can define to which class all functionality would be exported.
621             For the automatic pollution of strict() an warnings() you have to define the caller level, in which this behavior would
622             be exported.
623              
624             B For automatic export of strict() and warnings() behavior you have to call this method in an B method
625             at compiletime.
626              
627             =item run_check( ) return:VOID
628              
629             Helper method for static perl (see BUGS). This method check all declarations and implement parameter and return value checker.
630              
631             =item unimport( ) return:VOID
632              
633             Perl-intern method to provide the 'no Fukurama::Class' functionality. See section L above.
634              
635             =back
636              
637             =head1 AUTHOR
638              
639             Tobias Tacke, C<< >>
640              
641             =head1 BUGS
642              
643             This pragma you can only use for non-static perl. Most of the features use the perl-buildin CHECK-block,
644             but mod_perl or fastCGI doesn't support this block.
645              
646             In mod_perl you can "fake" this, if you say:
647              
648             Fukurama::Class->run_check();
649              
650             in the main-handler method and all is well. All compile-time checks would croak in this line, if there
651             are errors. Not fine but it works.
652              
653             I still have to discover hov the attributes like "Private" in Catalyst work. There must be a hack :)
654              
655             Please report any bugs or feature requests to
656             C, or through the web interface at
657             L.
658             I will be notified, and then you'll automatically be notified of any progress on
659             your bug as I make changes.
660              
661             =head1 SUPPORT
662              
663             You can find the documentation of this module with the perldoc command.
664              
665             perldoc Fukurama::Class
666              
667             You can also look for information at:
668              
669             =over 4
670              
671             =item * AnnoCPAN: Annotated CPAN documentation
672              
673             L
674              
675             =item * CPAN Ratings
676              
677             L
678              
679             =item * RT: CPAN's request tracker
680              
681             L
682              
683             =item * Search CPAN
684              
685             L
686              
687             =back
688              
689             =head1 ACKNOWLEDGEMENTS
690              
691             =head1 COPYRIGHT & LICENSE
692              
693             Copyright 2007 Tobias Tacke, all rights reserved.
694              
695             This program is free software; you can redistribute it and/or modify it
696             under the same terms as Perl itself.
697              
698             =cut
699              
700             1;