File Coverage

gen/attr-PerlBean.pl
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1 1     1   7 use strict;
  1         1  
  1         40  
2              
3 1     1   5 use PerlBean::Style qw(:codegen);
  1         3  
  1         1882  
4             my $pkg = 'PerlBean';
5              
6             push(@::bean_desc, {
7             bean_opt => {
8             abstract => 'Code generation for bean like Perl modules',
9             package => $pkg,
10             use_perl_version => 5.005,
11             short_description => 'Package to generate bean like Perl modules',
12             synopsis => &get_syn(),
13             description => <
14             The C<$pkg> class models a Perl module with one package. After adding different components to the C<$pkg>, the Perl module can be generated.
15              
16             The following sections in the code generated by a C<$pkg> are used to explain the concept.
17              
18             =over
19              
20             =item C<$pkg> module file header section
21              
22             package Circle;
23            
24             use 5.008;
25             use base qw( Shape Exporter );
26             use strict;
27             use warnings;
28             use Error qw(:try);
29             require Exporter;
30              
31             =over
32              
33             =item C
34              
35             is used to set the package name in C.
36              
37             =item C or C
38              
39             are used to add C<${pkg}::Dependency> objects like the C and C lines in the example. Note however that except for C all C dependencies in the example above are set by default when initializing a C<$pkg> object without specifying a C option.
40              
41             =item C
42              
43             is used to set the version number in the C dependency. By default the version number is set to C<\\\$]>. This is an exception to the C<${pkg}::Dependency> mechanism.
44              
45             =item C, C or C
46              
47             are used to express inheritance relationships. When the C<$pkg> is written, the inheritance relationships -like C in this example- appear in the C list. The C bit is there because symbols are exported by C.
48              
49             =back
50              
51             =item C<$pkg> symbols:
52              
53             =over
54              
55             =item C or C
56              
57             are used to add C<${pkg}::Symbol> objects. C<${pkg}::Symbol> objects are described in their own manual pages.
58              
59             =back
60              
61             =item C<$pkg> complimentary symbols:
62              
63             # Used by _value_is_allowed
64             our \%ALLOW_ISA = (
65             );
66            
67             # Used by _value_is_allowed
68             our \%ALLOW_REF = (
69             );
70            
71             # Used by _value_is_allowed
72             our \%ALLOW_RX = (
73             'radius' => [ '^\\d*(\\.\\d+)?\$' ],
74             );
75              
76             # Used by _value_is_allowed
77             our \%ALLOW_VALUE = (
78             );
79            
80             # Used by _initialize
81             our \%DEFAULT_VALUE = (
82             );
83              
84             # Package version
85             our (\$VERSION) = '\$Revision: 1.0 $' =~ /\\\$Revision:\\s+([^\\s]+)/;
86              
87             The C symbols above are used by the generated class to check rules that apply to the C<$pkg>'s attributes. They are not exported. You could theoretically overwrite them. But don't do that!
88              
89             The C symbol above is used at class instantiation to set the attribute's default values of the C. It is not exported. Sometimes you need to overwrite values. That's not particularly nice and should be addressed.
90              
91             The C is there to allow versioning through CVS. You could overwrite it.
92              
93             =item Preloaded section end
94              
95             1;
96            
97             __END__
98              
99             If the C<$pkg> is C then the code above is generated in order to autoload the methods that follow. The method C is used to change the autoload behavior of a C<$pkg>. NOTE: In my experience it pays to first have C<$pkg>s preloaded and to switch to autoload after debugging.
100              
101             =item NAME section
102              
103             =head1 NAME
104            
105             Circle - circle shape
106              
107             The package name ( which was set through C ) is put in C.
108              
109             =over
110              
111             =item C
112              
113             is used to set a short package description in C<- circle shape>.
114              
115             =back
116              
117             =item ABSTRACT section
118              
119             =head1 ABSTRACT
120            
121             circle shape
122              
123             =over
124              
125             =item C
126              
127             is used to set the abstract information in C.
128              
129             =back
130              
131             =item DESCRIPTION section
132              
133             =head1 DESCRIPTION
134            
135             circle shape
136              
137             =over
138              
139             =item C
140              
141             is used to set the description information C. If no description is set then CCircleE TODO> would be shown.
142              
143             =back
144              
145             =item EXPORT section
146              
147             This section describes all exported C<${pkg}::Symbol> objects like in the following example.
148              
149             =head1 EXPORT
150            
151             By default nothing is exported.
152            
153             =head2 geo
154            
155             Geometric constants
156            
157             =over
158            
159             =item \$PI
160            
161             The PI constant
162            
163             =back
164              
165             =item CONSTRUCTOR section
166              
167             All constructors are documented in alphabetical order in this section. C<$pkg> by default generates documentation for the C constructor. In theory you can overwrite the C constructor and hence alter the documentation thereof. Before you do so, I suggest you thoroughly contemplate this. You can of course add a C<${pkg}::Method::Constructor> object ( e.g. C ) in order to customize construction.
168              
169             =item METHODS section
170              
171             All methods that aren't constructors are documented in alphabetical order in this section. C<${pkg}::Method> objects in the C by default generate documentation for the methods. In theory you can overwrite the methods. Again, I suggest you thoroughly contemplate the consequences.
172              
173             =item SEE ALSO section
174              
175             L,
176             L,
177             L
178              
179             All C<$pkg> objects inside a C<${pkg}::Collection> are referred in this section as listed.
180              
181             =item BUGS section
182              
183             None known (yet.)
184              
185             This section always has C in it.
186              
187             =item HISTORY section
188              
189             First development: September 2003
190             Last update: September 2003
191              
192             This section always has Ccurrent_dateE Last update: CEcurrent_dateE> in it.
193              
194             =item AUTHOR section
195              
196             Vincenzo Zocca
197              
198             This section always has the B field from the C file.
199              
200             =item COPYRIGHT section
201              
202             Copyright 2003 by Vincenzo Zocca
203              
204             This section always contains the above message with the C and the B field from the C file.
205              
206             =item LICENSE section
207              
208             This code is licensed under B.
209             Details on L.
210              
211             This section either contains:
212              
213             1) The license of the C<$pkg> which set through method C
214              
215             2) The license of the C<${pkg}::Collection>
216              
217             3) The text C
218              
219             =item Implementation section
220              
221             This section contains the implementation of the methods and constructors. First listed are the constructors which are ordered alphabetically and C and C<_initialize()> are kept near to each-other. Then the normal methods are listed alphabetically.
222              
223             =item End of file
224              
225             1;
226              
227             If the C<$pkg> is not C then the code above is generated in order to close the file the I way. The method C is used to change the autoload behavior of a C<$pkg>. NOTE: In my experience it pays to first have C<$pkg>s preloaded and to switch to autoload after debugging.
228              
229             =back
230             EOF
231             },
232             attr_opt => [
233             {
234             method_factory_name => 'abstract',
235             type => 'SINGLE',
236             allow_rx => [qw(^.*$)],
237             short_description => 'the PerlBean\'s abstract (a one line description of the module)',
238             },
239             {
240             method_factory_name => 'method_factory',
241             type => 'MULTI',
242             unique => 1,
243             associative => 1,
244             method_key => 1,
245             id_method => 'get_method_factory_name',
246             short_description => 'the list of \'PerlBean::Method::Factory\' objects',
247             allow_isa => [ qw( PerlBean::Method::Factory ) ],
248             },
249             {
250             method_factory_name => 'base',
251             type => 'MULTI',
252             unique => 1,
253             ordered => 1,
254             short_description => 'the list of class names in use base',
255             allow_rx => [qw(^\S+$)],
256             },
257             {
258             method_factory_name => 'collection',
259             allow_isa => [qw(PerlBean::Collection)],
260             short_description => 'class to throw when exception occurs',
261             },
262             {
263             method_factory_name => 'description',
264             short_description => 'the PerlBean description',
265             },
266             {
267             method_factory_name => 'exception_class',
268             allow_empty => 0,
269             default_value => 'Error::Simple',
270             short_description => 'class to throw when exception occurs',
271             },
272             {
273             method_factory_name => 'autoloaded',
274             type => 'BOOLEAN',
275             short_description => 'the methods in the PerlBean are autoloaded',
276             default_value => 1,
277             },
278             {
279             method_factory_name => 'dependency',
280             type => 'MULTI',
281             unique => 1,
282             associative => 1,
283             method_key => 1,
284             id_method => 'get_dependency_name',
285             short_description => 'the list of \'PerlBean::Dependency\' objects',
286             allow_isa => [ qw( PerlBean::Dependency ) ],
287             default_value => [ 'XXXX' ],
288             },
289             {
290             method_factory_name => 'export_tag_description',
291             type => 'MULTI',
292             unique => 1,
293             associative => 1,
294             method_key => 1,
295             id_method => 'get_export_tag_name',
296             short_description => 'the list of \'PerlBean::Described::ExportTag\' objects',
297             allow_isa => [ qw( PerlBean::Described::ExportTag ) ],
298             },
299             {
300             method_factory_name => 'singleton',
301             type => 'BOOLEAN',
302             short_description => 'the package is a singleton and an C method is implemented',
303             default_value => 0,
304             },
305             {
306             method_factory_name => 'license',
307             type => 'SINGLE',
308             allow_rx => [qw(.*)],
309             short_description => 'the software license for the PerlBean',
310             },
311             {
312             method_factory_name => 'symbol',
313             type => 'MULTI',
314             unique => 1,
315             associative => 1,
316             method_key => 1,
317             id_method => 'get_symbol_name',
318             short_description => 'the list of \'PerlBean::Symbol\' objects',
319             allow_isa => [qw(PerlBean::Symbol)],
320             },
321             {
322             method_factory_name => 'method',
323             type => 'MULTI',
324             unique => 1,
325             associative => 1,
326             method_key => 1,
327             id_method => 'get_method_name',
328             short_description => 'the list of \'PerlBean::Method\' objects',
329             allow_isa => [qw(PerlBean::Method)],
330             },
331             {
332             method_factory_name => 'package',
333             allow_empty => 0,
334             mandatory => 1,
335             short_description => 'package name',
336             },
337             {
338             method_factory_name => 'use_perl_version',
339             allow_empty => 0,
340             default_value => '$]',
341             allow_rx => [ qw( ^v?\d+\(\.[\d_]+\)* ) ],
342             short_description => 'the Perl version to use',
343             },
344             {
345             method_factory_name => 'short_description',
346             short_description => 'the short PerlBean description',
347             default_value => 'NO DESCRIPTION AVAILABLE',
348             },
349             {
350             method_factory_name => 'synopsis',
351             type => 'SINGLE',
352             allow_rx => [qw(.*)],
353             short_description => 'the synopsis for the PerlBean',
354             },
355             {
356             method_factory_name => '_finalized_',
357             type => 'BOOLEAN',
358             documented => 0,
359             default_value => 0,
360             },
361             {
362             method_factory_name => '_has_exports_',
363             type => 'BOOLEAN',
364             documented => 0,
365             default_value => 0,
366             },
367             {
368             method_factory_name => '_export_tag_',
369             type => 'MULTI',
370             unique => 1,
371             associative => 1,
372             documented => 0,
373             description => <
374             Internal list of all accumulated export tags of the PerlBean's symbols.
375             EOF
376             },
377             ],
378             meth_opt => [
379             {
380             method_name => '_by_pragma',
381             documented => 0,
382             body => <
383             if (\$a =~ /^[a-z]/ && \$b !~ /^[a-z]/ ) {
384             return(-1);
385             }
386             elsif (\$a !~ /^[a-z]/ && \$b =~ /^[a-z]/ ) {
387             return(1);
388             }
389             else {
390             return(\$a cmp \$b );
391             }
392             EOF
393             },
394             {
395             method_name => '_get_overloaded_attribute',
396             documented => 0,
397             parameter_description => 'MATCH_ATTRIBUTE, LOOP_STOP',
398             description => <<'EOF',
399             Searches the superclass PerlBeans for an identically named attribute. C is the C object that must be matched in the search. C is used to detect loops in the inheritance. Returns a C if the search was successful and C otherwise.
400             EOF
401             body => <<'THE_EOF',
402             my $self = shift;
403             my $match_attr = shift;
404             my $loop_stop = shift;
405              
406             # Check for a loop
407             my $pkg = $self->get_package();
408             exists( $loop_stop->{$pkg} ) && throw Error::Simple("ERROR: PerlBean::_get_overloaded_attribute, loop detected in inheritance at bean '$pkg'.");
409             $loop_stop->{$pkg} = 1;
410              
411             # Check and return attribute if found in this bean
412             my $found_attr = ( $self->values_method_factory( $match_attr->get_method_factory_name() ) )[0];
413             if ( defined($found_attr) ) {
414             # Get the reference type of the attribute to match
415             my $match_attr_ref = ref($match_attr);
416              
417             # Get the reference type of the found attribute
418             my $found_attr_ref = ref($found_attr);
419              
420             # Match found if the reference types of the attribute to match and the found attribute are identical.
421             ( $match_attr_ref eq $found_attr_ref ) && return($found_attr);
422              
423             # The reference types of the attribute to match and the found attribute are different. Throw a usable exception.
424             my $name = $found_attr->get_method_factory_name();
425             my $match_attr_pkg = $match_attr->get_perl_bean()->get_package();
426             throw Error::Simple("ERROR: PerlBean::_get_overloaded_attribute, found an attribute named '$name' in package '$pkg' but the reference type '$found_attr_ref' was not as in package '$match_attr_pkg' ($match_attr_ref).");
427             }
428              
429             # Check super classes
430             foreach my $super_pkg ($self->get_base()) {
431             # Get the super class bean
432             my $super_bean = ( $self->get_collection()->values_perl_bean($super_pkg) )[0];
433              
434             # If the super class bean has no bean in the collection then no attribute is found
435             defined($super_bean) || return(undef);
436              
437             # See if the super class bean has an attribute
438             my $attr_over = $super_bean->_get_overloaded_attribute( $match_attr, $loop_stop );
439              
440             # Return the overloaded bean if found
441             defined($attr_over) && return($attr_over);
442             }
443              
444             # Nothing found
445             return(undef);
446             THE_EOF
447             },
448             {
449             method_name => '_get_super_method',
450             documented => 0,
451             parameter_description => 'MATCH_METHOD, LOOP_STOP',
452             description => <<'EOF',
453             Searches the superclass PerlBeans for an identically named method. C is the C object that must be matched in the search. C is used to detect loops in the inheritance. Returns a C if the search was successful and C otherwise.
454             EOF
455             body => <<'THE_EOF',
456             my $self = shift;
457             my $match_meth = shift;
458             my $loop_stop = shift;
459              
460             # Check for a loop
461             my $pkg = $self->get_package();
462             exists( $loop_stop->{$pkg} ) && throw Error::Simple("ERROR: PerlBean::_get_super_method, loop detected in inheritance at bean '$pkg'.");
463             $loop_stop->{$pkg} = 1;
464              
465             # Check and return method if found in this bean
466             my $found_meth = ( $self->values_method( $match_meth->get_method_name() ) )[0];
467             defined($found_meth) && return($found_meth);
468              
469             # Check super classes
470             foreach my $super_pkg ($self->get_base()) {
471             # Get the super class bean
472             my $super_bean = ( $self->get_collection()->values_perl_bean($super_pkg) )[0];
473              
474             # If the super class bean has no bean in the collection then no method is found
475             defined($super_bean) || return(undef);
476              
477             # See if the super class bean has the method
478             my $found_meth = $super_bean->_get_super_method( $match_meth, $loop_stop );
479              
480             # Return the overloaded bean if found
481             defined($found_meth) && return($found_meth);
482             }
483              
484             # Nothing found
485             return(undef);
486             THE_EOF
487             },
488             {
489             method_name => '_get_effective_attributes',
490             documented => 0,
491             body => <<'THE_EOF',
492             my $self = shift;
493             my $done = shift;
494             my $loop_stop = shift || {};
495              
496             # Check for a loop
497             my $pkg = $self->get_package();
498             exists( $loop_stop->{$pkg} ) && throw Error::Simple("ERROR: PerlBean::_get_effective_attributes, loop detected for bean '$pkg'.");
499             $loop_stop->{$pkg} = 1;
500              
501             # Add own attributes
502             foreach my $method_factory ( $self->values_method_factory() ) {
503             # Only do attributes
504             $method_factory->isa( 'PerlBean::Attribute' ) || next;
505              
506             # Only do not done
507             exists( $done->{ $method_factory->get_method_factory_name() } ) && next;
508              
509             # Remember the attribute by name
510             $done->{ $method_factory->get_method_factory_name() } = $method_factory;
511             }
512              
513             # Add attributes from super classes
514             foreach my $super_pkg ($self->get_base()) {
515             # Get the super class bean
516             my $super_bean = ($self->get_collection()->values_perl_bean($super_pkg))[0];
517              
518             # If the super package is not in the collection, well too bad (for now anyway)
519             defined($super_bean) || next;
520              
521             # See if the super class bean has an attribute
522             $super_bean->_get_effective_attributes( $done, $loop_stop );
523             }
524             THE_EOF
525             },
526             {
527             method_name => '_get_effective_methods',
528             documented => 0,
529             body => <<'THE_EOF',
530             my $self = shift;
531             my $eff_meth = shift;
532             my $loop_stop = shift || {};
533              
534             # Check for a loop
535             my $pkg = $self->get_package();
536             exists( $loop_stop->{$pkg} ) && throw Error::Simple("ERROR: PerlBean::_get_effective_methods, loop detected for bean '$pkg'.");
537             $loop_stop->{$pkg} = 1;
538              
539             # Add own methods
540             foreach my $meth ( $self->values_method() ) {
541             exists( $eff_meth->{ $meth->get_method_name() } ) && next;
542             $eff_meth->{ $meth->get_method_name() } = $meth;
543             }
544              
545             # End if collection not set
546             defined( $self->get_collection() ) || return;
547              
548             # Add methods from super classes
549             foreach my $super_pkg ( $self->get_base() ) {
550             # Get the super class bean
551             my $super_bean = ( $self->get_collection()->values_perl_bean($super_pkg) )[0];
552              
553             # If the super package is not in the collection, well too bad (for now anyway)
554             defined($super_bean) || next;
555              
556             # See if the super class bean has an attribute
557             $super_bean->_get_effective_methods( $eff_meth, $loop_stop );
558             }
559             THE_EOF
560             },
561             {
562             method_name => '_finalize',
563             documented => 0,
564             description => <<'EOF',
565             Finalize the object by:
566             1) removing volatile methods and symbol
567             2) checking for exports
568             3) making the singleton symbol and method
569             4) making autoload thingies,
570             5) making 'use base' for inheritance
571             6) exporting symbols
572             7) making the $VERSION symbol
573             8) adding methods from the attribute factories
574             9) calling set__finalized_(1)
575             EOF
576             body => <<'EOF',
577             my $self = shift;
578              
579             # Remove all volatile dependencies
580             $self->_rm_volatile_dependencies();
581              
582             # Remove all volatile methods
583             $self->_rm_volatile_methods();
584              
585             # Remove all volatile symbols
586             $self->_rm_volatile_symbols();
587              
588             # Check if exporter is needed
589             $self->_mk__has_exports_();
590              
591             # Finalize constructor
592             $self->_finalize_constructor();
593              
594             # Finalize singleton
595             $self->_finalize_singleton();
596              
597             # Finalize autoload
598             $self->_finalize_autoload();
599              
600             # Finalize allowed
601             $self->_finalize_allowed();
602              
603             # Finalize default values
604             $self->_finalize_default();
605              
606             # Finalize 'use base'
607             $self->_finalize_use_base();
608              
609             # Finalize exports
610             $self->_finalize_exports();
611              
612             # Finalize version
613             $self->_finalize_version();
614              
615             # Finalize method factories
616             $self->_finalize_method_factories();
617              
618             # Remember this object is finalized
619             $self->set__finalized_(1);
620             EOF
621             },
622             {
623             method_name => '_finalize_allowed',
624             documented => 0,
625             description => <<'EOF',
626             Finalized the allowed thingies by:
627             1) checking if constraints apply
628             2) deleting constraint symbols if no constraints
629             3) adding the constraint symbols if constraints apply
630             4) adding the _value_is_allowed() method
631             EOF
632             body => <<'EOF',
633             my $self = shift;
634              
635             # Check for constraints
636             my $constraints = 0;
637             my $has_attributes = 0;
638             foreach my $method_factory ( $self->values_method_factory() ) {
639             # Only check attributes
640             $method_factory->isa( 'PerlBean::Attribute' ) || next;
641              
642             # Remember we actually found attributes
643             $has_attributes = 1;
644              
645             # Check for constraints
646             $constraints =
647             $method_factory->write_allow_isa() ||
648             $method_factory->write_allow_ref() ||
649             $method_factory->write_allow_rx() ||
650             $method_factory->write_allow_value();
651             $constraints && last;
652             }
653              
654             # Make _value_allowed
655             $self->_mk_value_allowed_method($constraints, $has_attributes);
656              
657             # Delete the allow symbols if no constraints
658             $constraints ||
659             $self->delete_symbol( qw( %ALLOW_ISA %ALLOW_REF
660             %ALLOW_RX %ALLOW_VALUE ) );
661              
662             # Return if no constraints
663             $constraints || return();
664              
665             # %ALLOW_ISA symbol
666             my $assignment = "(\n";
667             foreach my $name ( sort( $self->keys_method_factory() ) ) {
668             # Make method factory out of name
669             my $method_factory = ( $self->values_method_factory($name) )[0];
670              
671             # Only do attributes
672             $method_factory->isa( 'PerlBean::Attribute' ) || next;
673              
674             $assignment .= $method_factory->write_allow_isa();
675             }
676             $assignment .= ");\n";
677             $self->add_symbol( PerlBean::Symbol->new( {
678             symbol_name => '%ALLOW_ISA',
679             assignment => $assignment,
680             comment => "# Used by _value_is_allowed\n",
681             volatile => 1,
682             } ) );
683              
684             # %ALLOW_REF symbol
685             $assignment = "(\n";
686             foreach my $name ( sort( $self->keys_method_factory() ) ) {
687             # Make method factory out of name
688             my $method_factory = ( $self->values_method_factory($name) )[0];
689              
690             # Only do attributes
691             $method_factory->isa( 'PerlBean::Attribute' ) || next;
692              
693             $assignment .= $method_factory->write_allow_ref();
694             }
695             $assignment .= ");\n";
696             $self->add_symbol( PerlBean::Symbol->new( {
697             symbol_name => '%ALLOW_REF',
698             assignment => $assignment,
699             comment => "# Used by _value_is_allowed\n",
700             volatile => 1,
701             } ) );
702              
703             # %ALLOW_RX symbol
704             $assignment = "(\n";
705             foreach my $name ( sort( $self->keys_method_factory() ) ) {
706             # Make method factory out of name
707             my $method_factory = ( $self->values_method_factory($name) )[0];
708              
709             # Only do attributes
710             $method_factory->isa( 'PerlBean::Attribute' ) || next;
711              
712             $assignment .= $method_factory->write_allow_rx();
713             }
714             $assignment .= ");\n";
715             $self->add_symbol( PerlBean::Symbol->new( {
716             symbol_name => '%ALLOW_RX',
717             assignment => $assignment,
718             comment => "# Used by _value_is_allowed\n",
719             volatile => 1,
720             } ) );
721              
722             # %ALLOW_VALUE symbol
723             $assignment = "(\n";
724             foreach my $name ( sort( $self->keys_method_factory() ) ) {
725             # Make method factory out of name
726             my $method_factory = ( $self->values_method_factory($name) )[0];
727              
728             # Only do attributes
729             $method_factory->isa( 'PerlBean::Attribute' ) || next;
730              
731             $assignment .= $method_factory->write_allow_value();
732             }
733             $assignment .= ");\n";
734             $self->add_symbol( PerlBean::Symbol->new( {
735             symbol_name => '%ALLOW_VALUE',
736             assignment => $assignment,
737             comment => "# Used by _value_is_allowed\n",
738             volatile => 1,
739             } ) );
740             EOF
741             },
742             {
743             method_name => '_finalize_constructor',
744             documented => 0,
745             description => <<'EOF',
746             Create constructor methods and doc
747             EOF
748             body => <<'EOF',
749             my $self = shift;
750              
751             # Do nothing if new() and _initialize() exist already.
752             ! $self->exists_method('new') ||
753             ! $self->exists_method('_initialize') ||
754             return;
755              
756             # The own attributes
757             my %own_attr = ();
758             foreach my $method_factory ( $self->values_method_factory() ) {
759              
760             # Only do attributes
761             $method_factory->isa( 'PerlBean::Attribute' ) || next;
762              
763             # Remember the attribute by name
764             $own_attr{ $method_factory->get_method_factory_name() } =
765             $method_factory;
766             }
767              
768             # Get the effective attributes for this bean, remember if one or more
769             # attributes are mandatory and remember all package names
770             $self->_get_effective_attributes( \my %eff_attr );
771             my $mand = 0;
772             my %eff_pkg = ();
773             foreach my $attr ( values(%eff_attr) ) {
774             # Is the attribute mandatory?
775             $mand ||= $attr->is_mandatory();
776              
777             # Remember the package name
778             $eff_pkg{ $attr->get_package() }{ $attr->get_method_factory_name() } =
779             $attr;
780             }
781              
782             # Make if new() method if it doesn't already exists
783             $self->exists_method('new') ||
784             $self->_finalize_constructor_new( \%own_attr, \%eff_pkg, $mand );
785              
786             # Make if _initialize() method if it doesn't already exists
787             $self->exists_method('_initialize') ||
788             $self->_finalize_constructor_initialize( \%own_attr );
789             EOF
790             },
791             {
792             method_name => '_finalize_constructor_initialize',
793             documented => 0,
794             description => <<'EOF',
795             Create _initialize() method if necessary
796             EOF
797             body => <<'THE_EOF',
798             my $self = shift;
799             my $own_attr = shift;
800              
801             # Implement _initialize() only if:
802             # 1) the PerlBean has own attributes
803             # 2) the PerlBean is not derived
804             # 3) the PerlBean has more than one superclass
805             # 4) the one superclass of the PerlBean's is not in the collection
806             # 1)
807             my $do_implement = scalar( keys( %{$own_attr} ) );
808             # 2)
809             $do_implement ||= ! scalar( $self->get_base() );
810             # 3)
811             $do_implement ||= scalar( $self->get_base() ) > 1;
812             # 4)
813             if ( ! $do_implement &&
814             defined( $self->get_collection() ) &&
815             scalar( $self->get_base() ) ) {
816             my $super_in_collection = 1;
817             foreach my $base ( $self->get_base() ) {
818             $super_in_collection &&= scalar( $self->get_collection()->
819             values_perl_bean($base) );
820             }
821             $do_implement = ! $super_in_collection;
822             }
823             $do_implement || return;
824              
825             my $pkg = $self->get_package();
826             my $ec = $self->get_exception_class();
827              
828             my $body = <
829             ${IND}my \$self${AO}=${AO}shift;
830             ${IND}my \$opt${AO}=${AO}defined${BFP}(\$_[0])${AO}?${AO}shift${AO}:${AO}\{};
831              
832             ${IND}# Check \$opt
833             ${IND}ref${BFP}(\$opt)${AO}eq${AO}'HASH'${AO}||${AO}throw $ec${BFP}("ERROR: ${pkg}::_initialize, first argument must be 'HASH' reference.");
834              
835             EOF
836              
837             # Add code for own attributes
838             foreach my $name ( sort( keys( %{$own_attr} ) ) ) {
839             $body .= $own_attr->{$name}->write_constructor_option_code();
840             }
841              
842             # superclass' _initialize
843             if ( scalar ( $self->get_base() ) == 1 ) {
844             $body .= <
845             ${IND}# Call the superclass' _initialize
846             ${IND}\$self->SUPER::_initialize${BFP}(\$opt);
847              
848             EOF
849             }
850             elsif ( scalar ( $self->get_base() ) ) {
851             $body .= <
852             ${IND}# Call the superclass' _initialize
853             EOF
854             foreach my $super ( $self->get_base() ) {
855             $body .= <
856             ${IND}\$self->${super}::_initialize${BFP}(\$opt);
857             EOF
858             }
859             $body .= "\n";
860             }
861              
862             # Code to return $self
863             $body .= <
864             ${IND}# Return \$self
865             ${IND}return${BFP}(\$self);
866             EOF
867              
868             # Make and add the method
869             $self->add_method( PerlBean::Method->new( {
870             method_name => '_initialize',
871             documented => 0,
872             volatile => 1,
873             body => $body,
874             } ) );
875             THE_EOF
876             },
877             {
878             method_name => '_finalize_constructor_new',
879             documented => 0,
880             description => <<'EOF',
881             Create new() method if necessary
882             EOF
883             body => <<'THE_EOF',
884             my $self = shift;
885             my $own_attr = shift;
886             my $eff_pkg = shift;
887             my $mand = shift;
888              
889             # Implement new() only if:
890             # 1) the PerlBean is not derived
891             # 2) not all the PerlBean's superclasses are in the collection
892             my $do_implement = ! scalar( $self->get_base() );
893             if ( ! $do_implement &&
894             defined( $self->get_collection() ) &&
895             scalar( $self->get_base() ) ) {
896             my $super_in_collection = 1;
897             foreach my $base ( $self->get_base() ) {
898             $super_in_collection &&= scalar( $self->get_collection()->
899             values_perl_bean($base) );
900             }
901             $do_implement = ! $super_in_collection;
902             }
903              
904             my $pkg = $self->get_package();
905             my $ec = $self->get_exception_class();
906              
907             # Describe OPT_HASH_REF if the PerlBean has attributes or its superclasses
908             # have.
909             my $do_opt_hash_ref = scalar( keys( %{$eff_pkg} ) );
910              
911             # Start the description
912             my $desc = "Creates a new C<$pkg> object.";
913             $desc .= ! $do_opt_hash_ref ? '' :
914             " C is a hash reference used to pass initialization options.";
915              
916             # If this PerlBean or its superclass PerlBeans have 'mandatory' attributes,
917             # then the OPT_HASH_REF parameter is mandatory
918             my $parameter_description = '';
919             if (! $do_opt_hash_ref) {
920             $desc .= "\n";
921             }
922             else {
923             $parameter_description = "${ACS}\[${ACS}OPT_HASH_REF${ACS}\]${ACS}";
924             if ($mand) {
925             $desc .= ' C is mandatory.';
926             $parameter_description = 'OPT_HASH_REF';
927             }
928              
929             # Add exception message to the description
930             $desc .= <
931             On error an exception C<$ec> is thrown.
932             EOF
933              
934             # Add pod for own attributes
935             if ( scalar( keys( %{$own_attr} ) ) ) {
936             $desc .= <
937              
938             Options for C may include:
939              
940             \=over
941             EOF
942             foreach my $name ( sort( keys( %{$own_attr} ) ) ) {
943             $desc .= $own_attr->{$name}->write_constructor_option_doc();
944             }
945              
946             # Close =over
947             $desc .= <
948              
949             \=back
950             EOF
951              
952             }
953              
954             # Add pod for inherited attributes
955             foreach my $pkg_name ( sort( keys( %{$eff_pkg} ) ) ) {
956             # Don't do own package
957             $pkg_name eq $self->get_package() && next;
958              
959             $desc .= <
960              
961             Options for C inherited through package B> may include:
962              
963             \=over
964             EOF
965              
966             foreach my $attr_name ( sort( keys( %{$eff_pkg->{$pkg_name}} ) ) ) {
967             $desc .= $eff_pkg->{$pkg_name}{$attr_name}->
968             write_constructor_option_doc();
969             }
970              
971             # Close =over
972             $desc .= <
973              
974             \=back
975             EOF
976             }
977             }
978              
979             # Make the body
980             my $body = <
981             ${IND}my \$class${AO}=${AO}shift;
982              
983             ${IND}my \$self${AO}=${AO}\{};
984             ${IND}bless${BFP}(${ACS}\$self,${AC}(${ACS}ref${BFP}(\$class)${AO}||${AO}\$class${ACS})${ACS});
985             ${IND}return${BFP}(${ACS}\$self->_initialize${BFP}(\@_)${ACS});
986             EOF
987              
988             # Make and add the method
989             $self->add_method( PerlBean::Method::Constructor->new( {
990             method_name => 'new',
991             parameter_description => $parameter_description,
992             volatile => 1,
993             description => $desc,
994             implemented => $do_implement,
995             body => $body,
996             } ) );
997             THE_EOF
998             },
999             {
1000             method_name => '_finalize_method_factories',
1001             documented => 0,
1002             description => <<'EOF',
1003             Create methods from the method factories and add them to the object if not already in the method.
1004             EOF
1005             body => <<'EOF',
1006             my $self = shift;
1007              
1008             # Add all methods from all method factories
1009             foreach my $method_factory ( $self->values_method_factory() ) {
1010              
1011             # Try adding each method from the factory
1012             foreach my $meth ( $method_factory->create_methods() ) {
1013             # Don't add the method if already present
1014             $self->exists_method( $meth->get_method_name() ) && next;
1015              
1016             # Add the method
1017             $self->add_method( $meth );
1018             }
1019             }
1020             EOF
1021             },
1022             {
1023             method_name => '_finalize_autoload',
1024             documented => 0,
1025             description => <<'EOF',
1026             Finalizes the AutoLoader thingies by:
1027             1) removing the AutoLoader dependency if not autoloaded
1028             2) adding the AutoLoader dependency if autoloaded and the dependency not
1029             already in object.
1030             EOF
1031             body => <<'EOF',
1032             my $self = shift;
1033              
1034             # Remove AutoLoader dependency if not autoloaded
1035             $self->is_autoloaded() || $self->delete_dependency('AutoLoader');
1036              
1037             # Return if not autoloaded
1038             $self->is_autoloaded() || return;
1039              
1040             # Return if AutoLoader dependency already exists
1041             $self->exists_dependency('AutoLoader') && return;
1042              
1043             # Add AutoLoader dependency
1044             $self->add_dependency( PerlBean::Dependency::Use->new( {
1045             dependency_name => 'AutoLoader',
1046             import_list => [ 'qw(AUTOLOAD)' ],
1047             volatile => 1,
1048             } ) );
1049             EOF
1050             },
1051             {
1052             method_name => '_finalize_default',
1053             documented => 0,
1054             description => <<'EOF',
1055             Finalizes the %DEFAULT_VALUE symbol by:
1056             1) creating one if not already there
1057             EOF
1058             body => <<'EOF',
1059             my $self = shift;
1060              
1061             # Don't add the '%DEFAULT_VALUE' if it exists already
1062             $self->exists_symbol( '%DEFAULT_VALUE' ) && return();
1063              
1064             # %DEFAULT_VALUE symbol
1065             my $has_default_value = '';
1066             my $assignment = "(\n";
1067             foreach my $name ( sort( $self->keys_method_factory() ) ) {
1068             # Make method factory out of name
1069             my $method_factory = ( $self->values_method_factory($name) )[0];
1070              
1071             # Only do attributes
1072             $method_factory->isa( 'PerlBean::Attribute' ) || next;
1073              
1074             $assignment .= $method_factory->write_default_value();
1075             $has_default_value ||= $method_factory->write_default_value();
1076             }
1077             $assignment .= ");\n";
1078              
1079             # Don't add the '%DEFAULT_VALUE' if there aren't any default values
1080             $has_default_value || return();
1081              
1082             # Add the symbol
1083             $self->add_symbol( PerlBean::Symbol->new( {
1084             symbol_name => '%DEFAULT_VALUE',
1085             assignment => $assignment,
1086             comment => "# Used by _initialize\n",
1087             volatile => 1,
1088             } ) );
1089             EOF
1090             },
1091             {
1092             method_name => '_finalize_exports',
1093             documented => 0,
1094             description => <<'EOF',
1095             Finalizes the exporting by:
1096             1) adding 'require Exporter' dependency if is__has_exports_()
1097             2) deleting symbols %EXPORT_TAGS @EXPORT_OK @EXPORT if !is__has_exports_()
1098             3) adding symbols %EXPORT_TAGS @EXPORT_OK @EXPORT if not already present
1099             EOF
1100             body => <<'EOF',
1101             my $self = shift;
1102              
1103             # Delete the require Exporter dependency
1104             $self->delete_dependency('Exporter');
1105              
1106             # Delete %EXPORT_TAGS @EXPORT_OK @EXPORT if not exported
1107             $self->is__has_exports_() ||
1108             $self->delete_symbol( qw( %EXPORT_TAGS @EXPORT_OK @EXPORT ) );
1109              
1110             # That's it if no exports
1111             $self->is__has_exports_() || return;
1112              
1113             # require Exporter
1114             $self->add_dependency( PerlBean::Dependency::Require->new( {
1115             dependency_name => 'Exporter',
1116             volatile => 1,
1117             } ) );
1118              
1119             # Get all export tags
1120             $self->set__export_tag_();
1121             foreach my $sym ( $self->values_symbol() ) {
1122             foreach my $tag ( $sym->values_export_tag() ) {
1123             $self->exists__export_tag_($tag) ||
1124             $self->add__export_tag_($tag, []);
1125             push( @{ ( $self->values__export_tag_($tag) )[0] }, $sym );
1126             }
1127             }
1128              
1129              
1130             # Add %EXPORT_TAGS symbol if it doesn't already exist
1131             if ( ! $self->exists_symbol('%EXPORT_TAGS') ) {
1132             my $assignment = "(\n";
1133             foreach my $tag ( sort( $self->keys__export_tag_() ) ) {
1134              
1135             # The %EXPORT_TAGS assignment head for this tag
1136             $assignment .= "${IND}'$tag' => [ qw(\n";
1137              
1138             # Fill out the lines alphabetically
1139             foreach my $name ( sort( $self->keys_symbol() ) ) {
1140              
1141             # Get the symbol
1142             my $sym = ( $self->values_symbol($name) )[0];
1143              
1144             # Skip if not in tag
1145             $sym->exists_export_tag($tag) || next;
1146              
1147             # Add the line
1148             $assignment .= "${IND}${IND}$name\n";
1149             }
1150              
1151             # The %EXPORT_TAGS assignment tail for this tag
1152             $assignment .= "${IND}) ],\n";
1153             }
1154              
1155             # The %EXPORT_TAGS assignment tail
1156             $assignment .= ");\n";
1157              
1158             # Make and add the symbols %EXPORT_TAGS
1159             $self->add_symbol( PerlBean::Symbol->new( {
1160             symbol_name => '%EXPORT_TAGS',
1161             assignment => $assignment,
1162             comment => "# Exporter variable\n",
1163             volatile => 1,
1164             } ) );
1165             }
1166              
1167              
1168             # The @EXPORT_OK assignment head
1169             my $EOA = "qw(\n";
1170              
1171             # The @EXPORT assignment head
1172             my $EA = "qw(\n";
1173              
1174             # Fill $EOA and $EA
1175             foreach my $name ( sort( $self->keys_symbol() ) ) {
1176             # Get the symbol
1177             my $sym = ( $self->values_symbol($name) )[0];
1178              
1179             # Next if no tag
1180             $sym->values_export_tag() || next;
1181              
1182             # Add the line to $EOA
1183             $EOA .= "${IND}$name\n";
1184              
1185             # Next if no default tag
1186             $sym->exists_export_tag('default') || next;
1187              
1188             # Add the line to $EA
1189             $EA .= "${IND}$name\n";
1190              
1191             }
1192              
1193             # The @EXPORT_OK assignment tail
1194             $EOA .= ");\n";
1195              
1196             # The @EXPORT assignment tail
1197             $EA .= ");\n";
1198              
1199             # Add @EXPORT_OK symbol if it doesn't already exist
1200             ! $self->exists_symbol('@EXPORT_OK') &&
1201             $self->add_symbol( PerlBean::Symbol->new( {
1202             symbol_name => '@EXPORT_OK',
1203             assignment => $EOA,
1204             comment => "# Exporter variable\n",
1205             volatile => 1,
1206             } ) );
1207              
1208             # Add @EXPORT symbol if it doesn't already exist
1209             ! $self->exists_symbol('@EXPORT') &&
1210             $self->add_symbol( PerlBean::Symbol->new( {
1211             symbol_name => '@EXPORT',
1212             assignment => $EA,
1213             comment => "# Exporter variable\n",
1214             volatile => 1,
1215             } ) );
1216             EOF
1217             },
1218             {
1219             method_name => '_finalize_singleton',
1220             documented => 0,
1221             description => <<'EOF',
1222             Add a symbol $SINGLETON if it is not already in the object.
1223             Add the method instance() if it is not already in the object.
1224             EOF
1225             body => <<'THE_EOF',
1226             my $self = shift;
1227              
1228             $self->is_singleton() || return;
1229              
1230             # Make the $SINGLETON symbol if it doesn't exist already
1231             $self->exists_symbol('$SINGLETON') ||
1232             $self->add_symbol( PerlBean::Symbol->new( {
1233             symbol_name => '$SINGLETON',
1234             assignment => "undef;\n",
1235             comment => "# Singleton variable\n",
1236             volatile => 1,
1237             } ) );
1238              
1239             # Return if the instance() method already exists
1240             $self->exists_method('instance') && return();
1241              
1242             # Package name
1243             my $pkg = $self->get_package();
1244              
1245             # Make the instance() method
1246             $self->add_method( PerlBean::Method->new( {
1247             method_name => 'instance',
1248             parameter_description => ' [ CONSTR_OPT ] ',
1249             volatile => 1,
1250             description => <
1251             Always returns the same C<${pkg}> -singleton- object instance. The first time it is called, parameters C -if specified- are passed to the constructor.
1252             EOF
1253             body => <
1254             ${IND}# Allow calls like:
1255             ${IND}# - ${pkg}::instance()
1256             ${IND}# - ${pkg}->instance()
1257             ${IND}# - \$variable->instance()
1258             ${IND}if${BCP}(${ACS}ref${BFP}(\$_[0])${AO}&&${AO}&UNIVERSAL::isa(${ACS}\$_[0], '${pkg}'${ACS})${ACS}) {
1259             ${IND}${IND}shift;
1260             ${IND}}${PBCC[1]}elsif${BCP}(${ACS}!${AO}ref${BFP}(\$_[0])${AO}&&${AO}\$_[0]${AO}eq${AO}'${pkg}'${ACS})${PBOC[1]}{
1261             ${IND}${IND}shift;
1262             ${IND}}
1263              
1264             ${IND}# If \$SINGLETON is defined return it
1265             ${IND}defined${BFP}(\$SINGLETON) && return${BFP}(\$SINGLETON);
1266              
1267             ${IND}# Create the object and set \$SINGLETON
1268             ${IND}\$SINGLETON${AO}=${AO}${pkg}->new${BFP}();
1269              
1270             ${IND}# Initialize the object separately as the initialization might
1271             ${IND}# depend on \$SINGLETON being set.
1272             ${IND}\$SINGLETON->_initialize${BFP}(\@_);
1273              
1274             ${IND}# Return \$SINGLETON
1275             ${IND}return${BFP}(\$SINGLETON);
1276             EOF
1277             } ) );
1278             THE_EOF
1279             },
1280             {
1281             method_name => '_finalize_version',
1282             documented => 0,
1283             description => <<'EOF',
1284             Add $VERSION if it does not already exists
1285             EOF
1286             body => <<'EOF',
1287             my $self = shift;
1288              
1289             # Return if '$VERSION' or '($VERSION)' exists
1290             ( $self->exists_symbol('$VERSION') ||
1291             $self->exists_symbol('($VERSION)') ) && return();
1292              
1293             # Make the $VERSION symbol
1294             my $va = '\'$';
1295             $va .= 'Revision: 0.0.0.0';
1296             $va .= " \$'${AO}=~${AO}/\\\$";
1297             $va .= 'Revision:\\s+([^\\s]+)/;';
1298             $va .= "\n";
1299              
1300             # Add the ($VERSION) symbol
1301             $self->add_symbol( PerlBean::Symbol->new( {
1302             symbol_name => '($VERSION)',
1303             assignment => $va,
1304             comment => "# Package version\n",
1305             volatile =>1,
1306             } ) );
1307             EOF
1308             },
1309             {
1310             method_name => '_finalize_use_base',
1311             documented => 0,
1312             description => <<'EOF',
1313             Makes the 'use base' dependency for inheritance and for Exporter stuff
1314             EOF
1315             body => <<'EOF',
1316             my $self = shift;
1317              
1318             my @base = $self->get_base();
1319             $self->is__has_exports_() && push( @base, 'Exporter' );
1320             if ( scalar(@base) ) {
1321             my $dep = PerlBean::Dependency::Use->new( {
1322             dependency_name => 'base',
1323             import_list => [ "qw( @base )" ],
1324             volatile => 1,
1325             } );
1326             $self->add_dependency($dep);
1327             }
1328             EOF
1329             },
1330             {
1331             method_name => '_mk__has_exports_',
1332             documented => 0,
1333             description => <<'EOF',
1334             Check if symbols are exported.
1335             EOF
1336             body => <<'EOF',
1337             my $self = shift;
1338              
1339             # Check all symbols
1340             foreach my $sym ( $self->values_symbol() ) {
1341              
1342             # But discard the export symbols
1343             if ( $sym->get_symbol_name() eq '%EXPORT_TAGS' ||
1344             $sym->get_symbol_name() eq '@EXPORT_OK' ||
1345             $sym->get_symbol_name() eq '@EXPORT' ) {
1346             next;
1347             }
1348              
1349             # Check if the symbol is exported
1350             if ( scalar( $sym->values_export_tag() ) ) {
1351             $self->set__has_exports_(1);
1352             return;
1353             }
1354             }
1355              
1356             # Nothing found to export
1357             $self->set__has_exports_(0);
1358             EOF
1359             },
1360             {
1361             method_name => '_mk_value_allowed_method',
1362             documented => 0,
1363             body => <<'THE_EOF',
1364             my $self = shift;
1365             my $constraints = shift;
1366             my $has_attributes = shift;
1367              
1368             # Do nothing of not attributes
1369             $has_attributes || return();
1370              
1371             my $body = ! $constraints ? "${IND}return${BFP}(1);\n" : <
1372             ${IND}my \$name${AO}=${AO}shift;
1373              
1374             ${IND}# Value is allowed if no ALLOW clauses exist for the named attribute
1375             ${IND}if${BCP}(${ACS}!${AO}exists${BFP}(${ACS}\$ALLOW_ISA{\$name}${ACS})${AO}&&${AO}!${AO}exists${BFP}(${ACS}\$ALLOW_REF{\$name}${ACS})${AO}&&${AO}!${AO}exists${BFP}(${ACS}\$ALLOW_RX{\$name}${ACS})${AO}&&${AO}!${AO}exists${BFP}(${ACS}\$ALLOW_VALUE{\$name}${ACS})${ACS})${PBOC[1]}{
1376             ${IND}${IND}return${BFP}(1);
1377             ${IND}}
1378              
1379             ${IND}# At this point, all values in \@_ must to be allowed
1380             ${IND}CHECK_VALUES:
1381             ${IND}foreach my \$val (\@_)${PBOC[1]}{
1382             ${IND}${IND}# Check ALLOW_ISA
1383             ${IND}${IND}if${BCP}(${ACS}ref${BFP}(\$val)${AO}&&${AO}exists${BFP}(${ACS}\$ALLOW_ISA{\$name}${ACS})${ACS})${PBOC[2]}{
1384             ${IND}${IND}${IND}foreach my \$class (${ACS}\@{${ACS}\$ALLOW_ISA{\$name}${ACS}}${ACS})${PBOC[3]}{
1385             ${IND}${IND}${IND}${IND}&UNIVERSAL::isa${BFP}(${ACS}\$val,${AC}\$class${ACS})${AO}&&${AO}next CHECK_VALUES;
1386             ${IND}${IND}${IND}}
1387             ${IND}${IND}}
1388              
1389             ${IND}${IND}# Check ALLOW_REF
1390             ${IND}${IND}if${BCP}(${ACS}ref${BFP}(\$val)${AO}&&${AO}exists${BFP}(${ACS}\$ALLOW_REF{\$name}${ACS})${ACS})${PBOC[2]}{
1391             ${IND}${IND}${IND}exists${BFP}(${ACS}\$ALLOW_REF{\$name}{${ACS}ref${BFP}(\$val)${ACS}}${ACS})${AO}&&${AO}next CHECK_VALUES;
1392             ${IND}${IND}}
1393              
1394             ${IND}${IND}# Check ALLOW_RX
1395             ${IND}${IND}if${BCP}(${ACS}defined${BFP}(\$val)${AO}&&${AO}!${AO}ref${BFP}(\$val)${AO}&&${AO}exists${BFP}(${ACS}\$ALLOW_RX{\$name}${ACS})${ACS})${PBOC[2]}{
1396             ${IND}${IND}${IND}foreach my \$rx (${ACS}\@{${ACS}\$ALLOW_RX{\$name}${ACS}}${ACS})${PBOC[3]}{
1397             ${IND}${IND}${IND}${IND}\$val${AO}=~${AO}/\$rx/${AO}&&${AO}next CHECK_VALUES;
1398             ${IND}${IND}${IND}}
1399             ${IND}${IND}}
1400              
1401             ${IND}${IND}# Check ALLOW_VALUE
1402             ${IND}${IND}if${BCP}(${ACS}!${AO}ref${BFP}(\$val)${AO}&&${AO}exists${BFP}(${ACS}\$ALLOW_VALUE{\$name}${ACS})${ACS})${PBOC[2]}{
1403             ${IND}${IND}${IND}exists${BFP}(${ACS}\$ALLOW_VALUE{\$name}{\$val}${ACS})${AO}&&${AO}next CHECK_VALUES;
1404             ${IND}${IND}}
1405              
1406             ${IND}${IND}# We caught a not allowed value
1407             ${IND}${IND}return${BFP}(0);
1408             ${IND}}
1409              
1410             ${IND}# OK, all values are allowed
1411             ${IND}return${BFP}(1);
1412             EOF
1413             $self->add_method( PerlBean::Method->new( {
1414             method_name => '_value_is_allowed',
1415             volatile => 1,
1416             documented => 0,
1417             body => $body,
1418             } ) );
1419             THE_EOF
1420             },
1421             {
1422             method_name => '_rm_volatile_dependencies',
1423             documented => 0,
1424             description => <<'EOF',
1425             Remove all volatile methods from the object.
1426             EOF
1427             body => <<'EOF',
1428             my $self = shift;
1429              
1430             # Remove all dependencies that are volatile
1431             foreach my $dependency ( $self->values_dependency() ) {
1432             $dependency->is_volatile() || next;
1433             $self->delete_dependency( $dependency->get_dependency_name() );
1434             }
1435             EOF
1436             },
1437             {
1438             method_name => '_rm_volatile_methods',
1439             documented => 0,
1440             description => <<'EOF',
1441             Remove all volatile methods from the object.
1442             EOF
1443             body => <<'EOF',
1444             my $self = shift;
1445              
1446             # Remove all methods that are volatile
1447             foreach my $method ( $self->values_method() ) {
1448             $method->is_volatile() || next;
1449             $self->delete_method( $method->get_method_name() );
1450             }
1451             EOF
1452             },
1453             {
1454             method_name => '_rm_volatile_symbols',
1455             documented => 0,
1456             description => <<'EOF',
1457             Remove all volatile symbols from the object.
1458             EOF
1459             body => <<'EOF',
1460             my $self = shift;
1461              
1462             # Remove all symbols that are volatile
1463             foreach my $symbol ( $self->values_symbol() ) {
1464             $symbol->is_volatile() || next;
1465             $self->delete_symbol( $symbol->get_symbol_name() );
1466             }
1467             EOF
1468             },
1469             {
1470             method_name => '_write_constructors_doc',
1471             documented => 0,
1472             body => <<'THE_EOF',
1473             my $self = shift;
1474             my $fh = shift;
1475             my $eff_meth = shift;
1476              
1477             # Start section
1478             $fh->print(<
1479             \=head1 CONSTRUCTOR
1480              
1481             EOF
1482              
1483             # Do we have constructors?
1484             my $do_constructors = 0;
1485             foreach my $method ( values( %{$eff_meth} ) ) {
1486             $do_constructors ||= $method->isa('PerlBean::Method::Constructor');
1487             $do_constructors && last;
1488             }
1489              
1490             # If no constructors
1491             if (! $do_constructors) {
1492             $fh->print(<
1493             None
1494              
1495             EOF
1496              
1497             return;
1498             }
1499              
1500             $fh->print(<
1501             \=over
1502              
1503             EOF
1504             # Write constructors documentation
1505             foreach my $name ( sort( keys( ( %{$eff_meth} ) ) ) ) {
1506             my $method = $eff_meth->{$name};
1507             $method->isa('PerlBean::Method::Constructor') || next;
1508             $method->write_pod( $fh, $self->get_package() );
1509             }
1510              
1511             # Close =over
1512             $fh->print(<
1513             \=back
1514              
1515             EOF
1516             THE_EOF
1517             },
1518             {
1519             method_name => '_write_declared_symbols',
1520             documented => 0,
1521             body => <<'THE_EOF',
1522             my $self = shift;
1523             my $fh = shift;
1524              
1525             foreach my $name ( sort( $self->keys_symbol() ) ) {
1526             my $symbol = ( $self->values_symbol($name) )[0];
1527              
1528             $symbol->write($fh);
1529             }
1530             THE_EOF
1531             },
1532             {
1533             method_name => '_write_dependencies',
1534             documented => 0,
1535             body => <<'THE_EOF',
1536             my $self = shift;
1537             my $fh = shift;
1538              
1539             # Perl version
1540             my $pv = $self->get_use_perl_version();
1541             $fh->print("use $pv;\n");
1542              
1543             # Write PerlBean::Dependency::Use
1544             foreach my $dependency_name ( sort {&_by_pragma}
1545             ( $self->keys_dependency() ) ) {
1546             my $dep = ( $self->values_dependency($dependency_name) )[0];
1547              
1548             $dep->isa('PerlBean::Dependency::Use') || next;
1549              
1550             $dep->write($fh);
1551             }
1552              
1553             # Write PerlBean::Dependency::Require
1554             foreach my $dependency_name ( sort {&_by_pragma}
1555             ( $self->keys_dependency() ) ) {
1556             my $dep = ( $self->values_dependency($dependency_name) )[0];
1557              
1558             $dep->isa('PerlBean::Dependency::Require') || next;
1559              
1560             $dep->write($fh);
1561             }
1562              
1563             # Write PerlBean::Dependency::Import
1564             foreach my $dependency_name ( sort {&_by_pragma}
1565             ( $self->keys_dependency() ) ) {
1566             my $dep = ( $self->values_dependency($dependency_name) )[0];
1567              
1568             $dep->isa('PerlBean::Dependency::Import') || next;
1569              
1570             $dep->write($fh);
1571             }
1572              
1573             $fh->print("\n");
1574             THE_EOF
1575             },
1576             {
1577             method_name => '_write_file_end',
1578             documented => 0,
1579             body => <<'THE_EOF',
1580             my $self = shift;
1581             my $fh = shift;
1582              
1583             # Close the file with a '1;' only if not autoloaded
1584             $self->is_autoloaded() && return;
1585              
1586             $fh->print("1;\n");
1587             THE_EOF
1588             },
1589             {
1590             method_name => '_write_doc_export',
1591             documented => 0,
1592             body => <<'THE_EOF',
1593             my $self = shift;
1594             my $fh = shift;
1595              
1596             # Stop if no exports
1597             $self->is__has_exports_() || return;
1598              
1599             $fh->print( "=head1 EXPORT\n\n" );
1600              
1601             if ( ! $self->exists_export_tag_description('default') ) {
1602             $fh->print( "By default nothing is exported.\n\n" );
1603             }
1604              
1605             foreach my $tag ( sort( $self->keys__export_tag_() ) ) {
1606              
1607             $fh->print( "=head2 $tag\n\n" );
1608              
1609             if ( $self->exists_export_tag_description($tag) ) {
1610             my $tdesc = ( $self->values_export_tag_description($tag) )[0];
1611             $fh->print( $tdesc->get_description(), "\n" );
1612             } else {
1613             $fh->print( "TODO\n\n" );
1614             }
1615              
1616             $fh->print( "=over\n\n" );
1617              
1618             foreach my $name ( sort( $self->keys_symbol() ) ) {
1619              
1620             # Get the symbol
1621             my $sym = ( $self->values_symbol($name) )[0];
1622              
1623             # Skip if not in tag
1624             $sym->exists_export_tag($tag) || next;
1625              
1626             # Add the lines
1627             $fh->print( "=item $name\n\n" );
1628              
1629             $fh->print( $sym->get_description(), "\n" );
1630             }
1631              
1632             $fh->print( "=back\n\n" );
1633             }
1634             THE_EOF
1635             },
1636             {
1637             method_name => '_write_doc_head',
1638             documented => 0,
1639             body => <<'THE_EOF',
1640             my $self = shift;
1641             my $fh = shift;
1642              
1643             my $pkg = $self->get_package();
1644             my $sdesc = $self->get_short_description();
1645              
1646             my $desc = defined($self->get_description()) ?
1647             $self->get_description() : "C<$pkg> TODO\n";
1648              
1649             my $syn = defined($self->get_synopsis()) ?
1650             $self->get_synopsis() : " TODO\n";
1651              
1652             my $abs = defined($self->get_abstract()) ?
1653             $self->get_abstract() : 'TODO';
1654              
1655             $fh->print( "=head1 NAME\n\n" );
1656             $fh->print( "${pkg} - ${sdesc}\n\n" );
1657              
1658             $fh->print( "=head1 SYNOPSIS\n\n" );
1659             $fh->print( "${syn}\n" );
1660              
1661             $fh->print( "=head1 ABSTRACT\n\n" );
1662             $fh->print( "${abs}\n\n" );
1663              
1664             $fh->print( "=head1 DESCRIPTION\n\n" );
1665             $fh->print( "${desc}\n" );
1666             THE_EOF
1667             },
1668             {
1669             method_name => '_write_doc_tail',
1670             documented => 0,
1671             body => <<'THE_EOF',
1672             my $self = shift;
1673             my $fh = shift;
1674              
1675             my $m = $MON[(localtime())[4]];
1676             my $y = (localtime())[5] + 1900;
1677             my $p = (getpwuid($>))[6];
1678              
1679             my $also = 'TODO';
1680             if (defined($self->get_collection())) {
1681             $also = '';
1682             foreach my $pkg (sort($self->get_collection()->keys_perl_bean())) {
1683             next if ($pkg eq $self->get_package());
1684             $also .= "L<$pkg>,\n";
1685             }
1686             chop($also);
1687             chop($also);
1688             $also = $also ? $also : 'NONE';
1689             }
1690              
1691             my $lic = 'TODO';
1692             if (defined($self->get_license())) {
1693             $lic = $self->get_license();
1694             }
1695             elsif (defined($self->get_collection()) && defined($self->get_collection()->get_license())) {
1696             $lic = $self->get_collection()->get_license();
1697             }
1698              
1699             $fh->print(<
1700             \=head1 SEE ALSO
1701              
1702             $also
1703              
1704             \=head1 BUGS
1705              
1706             None known (yet.)
1707              
1708             \=head1 HISTORY
1709              
1710             First development: ${m} ${y}
1711             Last update: ${m} ${y}
1712              
1713             \=head1 AUTHOR
1714              
1715             ${p}
1716              
1717             \=head1 COPYRIGHT
1718              
1719             Copyright ${y} by ${p}
1720              
1721             \=head1 LICENSE
1722              
1723             $lic
1724             \=cut
1725              
1726             EOF
1727             THE_EOF
1728             },
1729             {
1730             method_name => '_write_methods_doc',
1731             documented => 0,
1732             body => <<'THE_EOF',
1733             my $self = shift;
1734             my $fh = shift;
1735             my $eff_meth = shift;
1736              
1737             # Start section
1738             $fh->print(<
1739             \=head1 METHODS
1740              
1741             EOF
1742              
1743             # Do we have methods?
1744             my $do_methods = 0;
1745             foreach my $method ( values( %{$eff_meth} ) ) {
1746             $do_methods ||= ! $method->isa('PerlBean::Method::Constructor');
1747             $do_methods && last;
1748             }
1749              
1750             # If no methods
1751             if (! $do_methods) {
1752             $fh->print(<
1753             None
1754              
1755             EOF
1756              
1757             return;
1758             }
1759              
1760             $fh->print(<
1761             \=over
1762              
1763             EOF
1764             # Write constructors documentation
1765             foreach my $name ( sort( keys( ( %{$eff_meth} ) ) ) ) {
1766             my $method = $eff_meth->{$name};
1767             $method->isa('PerlBean::Method::Constructor') && next;
1768             $method->write_pod( $fh, $self->get_package() );
1769             }
1770              
1771             # Close =over
1772             $fh->print(<
1773             \=back
1774              
1775             EOF
1776             THE_EOF
1777             },
1778             {
1779             method_name => '_write_package_head',
1780             documented => 0,
1781             body => <<'THE_EOF',
1782             my $self = shift;
1783             my $fh = shift;
1784              
1785             my $pkg = $self->get_package();
1786             $fh->print("package $pkg;\n\n");
1787             THE_EOF
1788             },
1789             {
1790             method_name => '_write_preloaded_end',
1791             documented => 0,
1792             body => <<'THE_EOF',
1793             my $self = shift;
1794             my $fh = shift;
1795              
1796             # End preload only for non autoloaded beans
1797             $self->is_autoloaded() || return;
1798              
1799             $fh->print(<
1800             1;
1801              
1802             $END
1803              
1804             EOF
1805             THE_EOF
1806             },
1807             {
1808             method_name => '_unfinalize',
1809             documented => 0,
1810             description => <<'EOF',
1811             Un-finalize the object by:
1812             1) removing volatile methods and symbol
1813             2) calling set__finalized_(0)
1814             EOF
1815             body => <<'EOF',
1816             my $self = shift;
1817              
1818             # Remove all volatile dependencies
1819             $self->_rm_volatile_dependencies();
1820              
1821             # Remove all volatile methods
1822             $self->_rm_volatile_methods();
1823              
1824             # Remove all volatile symbols
1825             $self->_rm_volatile_symbols();
1826              
1827             # Remember this object is not finalized
1828             $self->set__finalized_(0);
1829             EOF
1830             },
1831             {
1832             method_name => 'write',
1833             parameter_description => 'FILEHANDLE',
1834             description => <
1835             Write the Perl class code to C. C is an C object. On error an exception C is thrown.
1836             EOF
1837             body => <<'THE_EOF',
1838             my $self = shift;
1839             my $fh = shift;
1840              
1841             # Finalize the package if necessary
1842             my $was_finalized = $self->is__finalized_();
1843             $self->is__finalized_() || $self->_finalize();
1844              
1845             # Package heading
1846             $self->_write_package_head($fh);
1847              
1848             # Dependencies
1849             $self->_write_dependencies($fh);
1850              
1851             # Declared symbols
1852             $self->_write_declared_symbols($fh);
1853              
1854             # End of preloaded methods
1855             $self->_write_preloaded_end($fh);
1856              
1857             # Start pod documentation
1858             $self->_write_doc_head($fh);
1859              
1860             # Write EXPORT documentation
1861             $self->_write_doc_export($fh);
1862              
1863             # Get all methods that are callable from this package
1864             $self->_get_effective_methods( \my %eff_meth );
1865              
1866             # Write CONSTRUCTOR documentation
1867             $self->_write_constructors_doc($fh, \%eff_meth);
1868              
1869             # Write METHODS documentation
1870             $self->_write_methods_doc($fh, \%eff_meth);
1871              
1872             # Finish pod documentation
1873             $self->_write_doc_tail($fh);
1874              
1875             # All constructor methods from this bean
1876             my %all_meth_ref = ();
1877             foreach my $name ( sort( $self->keys_method() ) ) {
1878             my $method = ( $self->values_method($name) )[0];
1879             $method->isa('PerlBean::Method::Constructor') || next;
1880             $method->write_code($fh);
1881             $all_meth_ref{$name} = $method;
1882             }
1883              
1884             # The _initialize method from this bean
1885             scalar( $self->values_method('_initialize') ) &&
1886             ( $self->values_method('_initialize') )[0]->write_code($fh);
1887              
1888             # All methods from this bean
1889             foreach my $name ( sort( $self->keys_method() ) ) {
1890             $name eq '_initialize' && next;
1891             my $method = ( $self->values_method($name) )[0];
1892             $method->isa('PerlBean::Method::Constructor') && next;
1893             $method->write_code($fh);
1894             $all_meth_ref{$name} = $method;
1895             }
1896              
1897             # End of file
1898             $self->_write_file_end($fh);
1899              
1900             # Un-finalize the package if necessary
1901             $was_finalized || $self->_unfinalize();
1902             THE_EOF
1903             },
1904             {
1905             method_name => 'add_attribute',
1906             parameter_description => ' See add_method_factory() ',
1907             description => <
1908             Legacy method. Writes a warning to STDERR and calls C. Will be discontinued from the 4th of April 2004 on.
1909             EOF
1910             body => <<'EOF',
1911             my $self = shift;
1912              
1913             $LEGACY_COUNT++;
1914             ( $LEGACY_COUNT < 4 ) && print STDERR "WARNING: PerlBean::add_attribute, this is a legacy support method and will be discontinued from the 4th of April 2004 on. Change your code to use add_method_factory().\nNOW!\n";
1915             ( $LEGACY_COUNT == 3 ) && print STDERR "Oh bother...\n";
1916              
1917             return( $self->add_method_factory(@_) );
1918             EOF
1919             },
1920             {
1921             method_name => 'delete_attribute',
1922             parameter_description => ' See delete_method_factory() ',
1923             description => <
1924             Legacy method. Writes a warning to STDERR and calls C. Will be discontinued from the 4th of April 2004 on.
1925             EOF
1926             body => <<'EOF',
1927             my $self = shift;
1928              
1929             $LEGACY_COUNT++;
1930             ( $LEGACY_COUNT < 4 ) && print STDERR "WARNING: PerlBean::delete_attribute, this is a legacy support method and will be discontinued from the 4th of April 2004 on. Change your code to use delete_method_factory().\nNOW!\n";
1931             ( $LEGACY_COUNT == 3 ) && print STDERR "Oh bother...\n";
1932              
1933             return( $self->delete_method_factory(@_) );
1934             EOF
1935             },
1936             {
1937             method_name => 'exists_attribute',
1938             parameter_description => ' See exists_method_factory() ',
1939             description => <
1940             Legacy method. Writes a warning to STDERR and calls C. Will be discontinued from the 4th of April 2004 on.
1941             EOF
1942             body => <<'EOF',
1943             my $self = shift;
1944              
1945             $LEGACY_COUNT++;
1946             ( $LEGACY_COUNT < 4 ) && print STDERR "WARNING: PerlBean::exists_attribute, this is a legacy support method and will be discontinued from the 4th of April 2004 on. Change your code to use exists_method_factory().\nNOW!\n";
1947             ( $LEGACY_COUNT == 3 ) && print STDERR "Oh bother...\n";
1948              
1949             return( $self->exists_method_factory(@_) );
1950             EOF
1951             },
1952             {
1953             method_name => 'keys_attribute',
1954             parameter_description => ' See keys_method_factory() ',
1955             description => <
1956             Legacy method. Writes a warning to STDERR and calls C. Will be discontinued from the 4th of April 2004 on.
1957             EOF
1958             body => <<'EOF',
1959             my $self = shift;
1960              
1961             $LEGACY_COUNT++;
1962             ( $LEGACY_COUNT < 4 ) && print STDERR "WARNING: PerlBean::keys_attribute, this is a legacy support method and will be discontinued from the 4th of April 2004 on. Change your code to use keys_method_factory().\nNOW!\n";
1963             ( $LEGACY_COUNT == 3 ) && print STDERR "Oh bother...\n";
1964              
1965             return( $self->keys_method_factory(@_) );
1966             EOF
1967             },
1968             {
1969             method_name => 'set_attribute',
1970             parameter_description => ' See set_method_factory() ',
1971             description => <
1972             Legacy method. Writes a warning to STDERR and calls C. Will be discontinued from the 4th of April 2004 on.
1973             EOF
1974             body => <<'EOF',
1975             my $self = shift;
1976              
1977             $LEGACY_COUNT++;
1978             ( $LEGACY_COUNT < 4 ) && print STDERR "WARNING: PerlBean::set_attribute, this is a legacy support method and will be discontinued from the 4th of April 2004 on. Change your code to use set_method_factory().\nNOW!\n";
1979             ( $LEGACY_COUNT == 3 ) && print STDERR "Oh bother...\n";
1980              
1981             return( $self->set_method_factory(@_) );
1982             EOF
1983             },
1984             {
1985             method_name => 'values_attribute',
1986             parameter_description => ' See values_method_factory() ',
1987             description => <
1988             Legacy method. Writes a warning to STDERR and calls C. Will be discontinued from the 4th of April 2004 on.
1989             EOF
1990             body => <<'EOF',
1991             my $self = shift;
1992              
1993             $LEGACY_COUNT++;
1994             ( $LEGACY_COUNT < 4 ) && print STDERR "WARNING: PerlBean::values_attribute, this is a legacy support method and will be discontinued from the 4th of April 2004 on. Change your code to use values_method_factory().\nNOW!\n";
1995             ( $LEGACY_COUNT == 3 ) && print STDERR "Oh bother...\n";
1996              
1997             return( $self->values_method_factory(@_) );
1998             EOF
1999             },
2000             ],
2001             sym_opt => [
2002             {
2003             symbol_name => '$LEGACY_COUNT',
2004             comment => <
2005             # Legacy count variable
2006             EOF
2007             assignment => "0;\n",
2008             },
2009             {
2010             symbol_name => '$END',
2011             comment => <
2012             # Variable to not confuse AutoLoader
2013             EOF
2014             assignment => "'__END__';\n",
2015             },
2016             {
2017             symbol_name => '@MON',
2018             comment => <
2019             # Month names array
2020             EOF
2021             assignment => <
2022             qw(
2023             ${IND}January
2024             ${IND}February
2025             ${IND}March
2026             ${IND}April
2027             ${IND}May
2028             ${IND}June
2029             ${IND}July
2030             ${IND}August
2031             ${IND}September
2032             ${IND}October
2033             ${IND}November
2034             ${IND}December
2035             );
2036             EOF
2037             },
2038             ],
2039             use_opt => [
2040             {
2041             dependency_name => 'PerlBean::Method',
2042             },
2043             {
2044             dependency_name => 'PerlBean::Method::Constructor',
2045             },
2046             {
2047             dependency_name => 'PerlBean::Style',
2048             import_list => [ 'qw(:codegen)' ],
2049             },
2050             {
2051             dependency_name => 'PerlBean::Symbol',
2052             },
2053             {
2054             dependency_name => 'PerlBean::Dependency::Require',
2055             },
2056             {
2057             dependency_name => 'PerlBean::Dependency::Use',
2058             },
2059             ],
2060             } );
2061              
2062             sub get_syn {
2063 1     1   906 use IO::File;
  1         10735  
  1         298  
2064             my $fh = IO::File->new('< syn-PerlBean.pl');
2065             $fh = IO::File->new('< gen/syn-PerlBean.pl') if (! defined($fh));
2066             my $syn = '';
2067             my $prev_line = $fh->getline ();
2068             while (my $line = $fh->getline ()) {
2069             $syn .= ' ' . $prev_line;
2070             $prev_line = $line;
2071             }
2072             return($syn);
2073             }
2074              
2075             1;
2076