File Coverage

lib/Su.pm
Criterion Covered Total %
statement 346 390 88.7
branch 158 236 66.9
condition 48 76 63.1
subroutine 36 39 92.3
pod 12 13 92.3
total 600 754 79.5


line stmt bran cond sub pod time code
1             package Su;
2              
3 13     13   293646 use strict;
  13         31  
  13         447  
4 13     13   67 use warnings;
  13         23  
  13         371  
5 13     13   62 use Exporter;
  13         23  
  13         575  
6 13     13   24567 use Data::Dumper;
  13         156173  
  13         1141  
7 13     13   116 use Carp;
  13         28  
  13         804  
8 13     13   3482 use Test::More;
  13         63710  
  13         132  
9 13     13   4094 use File::Path;
  13         28  
  13         914  
10              
11 13     13   6018 use Su::Process;
  13         114  
  13         91  
12 13     13   87 use Su::Template;
  13         23  
  13         65  
13 13     13   7169 use Su::Model;
  13         1747  
  13         91  
14 13     13   80 use Su::Log;
  13         21  
  13         381  
15              
16 13     13   76 use Fatal qw(mkpath open);
  13         19  
  13         146  
17              
18             our $VERSION = '0.110';
19              
20             our @ISA = qw(Exporter);
21              
22             our @EXPORT = qw(resolve setup gen_defs gen_model gen_proc);
23              
24             our $info_href = {};
25              
26             our $BASE_DIR = './';
27              
28             our $DEFS_DIR = 'Defs';
29              
30             our $DEFS_MODULE_NAME = "Defs";
31              
32             our $DEFAULT_MODEL_NAME = 'Model';
33              
34             our $DEFAULT_PROC_NAME = 'MainProc';
35              
36             # A relative path to place the .tmpl file.
37             our $SU_TMPL_DIR = '/Su/templates/';
38              
39             # The field name to define the global fields in Defs file.
40             our $GLOBAL_MODEL_FIELD = 'global_model_field';
41              
42             =head1 NAME
43              
44             Su - A simple application layer to divide and integrate data and processes in the Perl program.
45              
46             =head1 SYNOPSIS
47              
48             my $su = Su->new;
49             my $proc_result = $su->resolve('process_id');
50             print $proc_result;
51              
52             =head1 DESCRIPTION
53              
54             Su is a simple application framework that works as a thin layer to
55             divide data and process in your Perl program. This framework aims an
56             ease of maintenance and extension of your application.
57              
58             Su is a thin application layer, so you can use Su with many other
59             frameworks you prefer in many cases.
60              
61             Note that Su framework has nothing to do with unix C (switch
62             user) command.
63              
64             =head3 Prepare Data and Process file
65              
66             Su provides the method to generate the template of Model and Process.
67             You can use method C like the following:
68              
69             perl -MSu -e 'Su::generate("Pkg::SomeProc")'
70              
71             Then, the file F and F should be
72             generated.
73              
74             Now describe your data to the C<$model> field of the generated Model
75             file.
76              
77             my $model=
78             {
79             field_a =>'value_a'
80             };
81              
82             And describe your process code to the C method defined in the
83             generated Process file like the following:
84              
85             sub process{
86             my $self = shift if ref $_[0] eq __PACKAGE__;
87             my $param = shift;
88              
89             my $ret = "param:" . $param . " and model:" . $model->{field_a};
90             return $ret;
91             }
92              
93             =head3 Integrate Model and Process
94              
95             Su integrates Model and Processes using the definition file.
96             To generate the definition file, type the following command.
97              
98             perl -MSu -e 'Su::gen_defs()'
99              
100             Then describe your setting to the C<$defs> field defined in the
101             generated F file.
102              
103             my $defs =
104             {
105             some_entry_id =>
106             {
107             proc=>'Pkg::SomeProc',
108             model=>'Pkg::SomeModel',
109             },
110             };
111              
112             You can also generate F using the C method by
113             passing the parameter C<1> as a second parameter.
114              
115             perl -MSu=base,lib -e 'Su::generate("Pkg::SomeProc", 1)'
116              
117             Then the file F will be generated with Model and Process file.
118              
119             =head3 Run the process using Su
120              
121             You can call the process via Su by passing the entry id which defined in
122             the definition file F.
123              
124             my $su = Su->new;
125             my $result = $su->resolve('some_entry_id');
126              
127             To pass the parameters to the C method in Process, then pass
128             the additional parameter to the C method.
129              
130             my $result = $su->resolve('some_entry_id', 'param1');
131              
132             =head3 Other features Su provides
133              
134             Logging and string template are the feature su provides for
135             convinience. These features are frequently used in many kinds of
136             applications and you can use these features without any other
137             dependencies. Surely you can use other modules you prefer with Su
138             framework.
139              
140             =head2 Additional usage - Filters
141              
142             The map, reduce and scalar filters can be defined in the definition file.
143              
144             These filters are Perl module which has the method for filtering the
145             result of the process. (In case of C filter, method name is
146             C.) You can chain filter modules. The following code is a
147             sample definition which uses these filters.
148              
149             my $defs =
150             {
151             some_proc_id =>
152             {
153             proc=>'MainProc',
154             model=>'Pkg::MainModel',
155             map_filter=>'Pkg::FilterProc', # or ['Filter01','Filter02']
156             reduce_filter=>'Pkg::ReduceProc', # reduce filter can only apply at once.
157             scalar_filter=>'Pkg::ScalarProc', # or ['Filter01','Filter02']
158             }
159             };
160              
161             The filters Su recognizes are the followings.
162              
163             =over
164              
165             =item map_filter
166              
167             The perl module which has C method.
168             The parameter of this method is an array which is a result of the
169             'process' method of the Process or the chained map filter.
170             The C method must return the array data type.
171              
172             =item reduce_filter
173              
174             The perl module which has C method.
175             The parameter of this method is an array which is a result of the
176             'process' method of the Process.
177             If the map filters are defined in the C, then the map_filters
178             are applied to the result of the process before passed to the reduce
179             filter.
180             The C method must return the scalar data type.
181             Note that this method can't chain.
182              
183             =item scalar_filter
184              
185             The perl module which has C method.
186             The parameter of this method is a scalar which is a result of the
187             'process' method of the Process.
188             If the C and C are defined in the
189             C, then these filters are applied to the result of the
190             process before passed to the scalar filter.
191              
192             The C method must return the scalar data type.
193              
194             =back
195              
196             =head1 ATTRIBUTES
197              
198             =head2 C<$MODEL_LOCALE>
199              
200             Set the locale string like 'ja_JP' to load locale specific Model
201             module. Locale specific Model has the postfix in it's name like
202             'Pkg::ModelName__ja_JP'.
203              
204             Then you should set the locale like this.
205              
206             $Su::MODEL_LOCALE = 'ja_JP';
207              
208             =cut
209              
210             our $MODEL_LOCALE = '';
211              
212             =head2 C<$MODEL_KEY_PREFIX>
213              
214             The hash reference which contains the key prefixes of the Model.
215             The key of this hash is a name of the model to apply this prefix.
216              
217             $MODEL_KEY_PREFIX = {
218             'pkg::SomeModel'=>'pre1',
219             };
220              
221             In this example, the key string 'pre1_key1' defined in
222             'pkg::SomeModel' is automatically converted to 'key1'. So you can
223             access customized value using key 'key1'.
224              
225             If the modified key is not exist, then the value of original key
226             should used.
227              
228             =cut
229              
230             our $MODEL_KEY_PREFIX = {};
231              
232             =head2 C<$MODEL_KEY_POSTFIX>
233              
234             The hash reference which contains the key postfixes of the Model.
235             The key of this hash is a name of the model to apply this postfix.
236              
237             This variable work same as $MODEL_KEY_PREFIX.
238              
239             =cut
240              
241             our $MODEL_KEY_POSTFIX = {};
242              
243             =begin comment
244              
245             The flag to use global defs setting set by the method Su::setup() directly, instead of read from Defs file.
246              
247             =end comment
248              
249             =cut
250              
251             our $USE_GLOBAL_SETUP = undef;
252              
253             =head1 METHODS
254              
255             =over
256              
257             =item import()
258              
259             use Su base=>'./base', proc=>'tmpls', model=>'models', defs=>'defs';
260              
261             If you want to specify some parameters from the command line, then it becomes like the following.
262              
263             perl -Ilib -MSu=base,./base,proc,tmpls,defs,models -e '{print "do some work";}'
264              
265             =cut
266              
267             sub import {
268 13     13   131 my $self = shift;
269              
270             # Save import list and remove from hash.
271 13         56 my %tmp_h = @_;
272 13         31 my $imports_aref = $tmp_h{import};
273              
274 13         31 delete $tmp_h{import};
275 13         34 my $base = $tmp_h{base};
276 13         36 my $template = $tmp_h{template};
277 13         27 my $defs = $tmp_h{defs};
278 13         29 my $model = $tmp_h{model};
279              
280             # print "base:" . Dumper($base) . "\n";
281             # print "template:" . Dumper($template) . "\n";
282             # print "model:" . Dumper($model) . "\n";
283             # print "defs:" . Dumper($defs) . "\n";
284             # $self->{logger}->trace( "base:" . Dumper($base) );
285             # $self->{logger}->trace( "template:" . Dumper($template) );
286             # $self->{logger}->trace( "model:" . Dumper($model) );
287             # $self->{logger}->trace( "defs:" . Dumper($defs) );
288 13         104 Su::Log->trace( "base:" . Dumper($base) );
289 13         146 Su::Log->trace( "template:" . Dumper($template) );
290 13         118 Su::Log->trace( "model:" . Dumper($model) );
291 13         113 Su::Log->trace( "defs:" . Dumper($defs) );
292              
293 13 50       119 $DEFS_DIR = $defs if $defs;
294 13 50       49 $Su::Template::TEMPLATE_DIR = $template if $template;
295 13 50       47 $Su::Model::MODEL_DIR = $model if $model;
296              
297             # If base is specified, then this setting effects to the all modules in Su package.
298 13 100       50 if ($base) {
299 13     13   73844 no warnings qw(once);
  13         26  
  13         40549  
300 5         13 $BASE_DIR = $base;
301 5         12 $Su::Template::TEMPLATE_BASE_DIR = $base;
302 5         16 $Su::Model::MODEL_BASE_DIR = $base;
303             } ## end if ($base)
304              
305 13 100 66     176 if ( $base || $template || $model || $defs ) {
      66        
      33        
306 5         13 $self->export_to_level( 1, $self, @{$imports_aref} );
  5         12246  
307             } else {
308              
309             # If '' or '' is not passed, then all of the parameters are required method names.
310 8         3548 $self->export_to_level( 1, $self, @_ );
311             }
312              
313             } ## end sub import
314              
315             =begin comment
316              
317             Load the definition file which binds process and model to the single entry.
318             The default definition file loaded by Su is F.
319             You can specify the loading definition file as a parameter of this method.
320              
321             $su->_load_defs_file();
322             $su->_load_defs_file('Defs::CustomDefs');
323              
324             If the Defs file is already loaded, do nothing and just return it's hash.
325              
326             If you want to reload defs file force, then pass the second parameter
327             as reload option.
328              
329             $su->_load_defs_file( "Defs::Defs", 1 );
330              
331             =end comment
332              
333             =cut
334              
335             our $defs_module_name;
336              
337             sub _load_defs_file {
338 36 100   36   5727 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
339              
340 36 100       134 my $BASE_DIR = $self->{base} ? $self->{base} : $BASE_DIR;
341 36 50       140 my $DEFS_DIR = $self->{defs} ? $self->{defs} : $DEFS_DIR;
342              
343             # Nothing to do if info is already set or loaded.
344             # if ( $info_href && keys %{$info_href} ) {
345             # return;
346             # }
347              
348 36   100     217 my $defs_mod_name = shift || "Defs::Defs";
349 36   100     156 my $b_force_reload = shift || undef;
350              
351 36 100       99 if ( !$b_force_reload ) {
352              
353             # Defs file tring to load is already loaded.
354 33 50       96 if ($self) {
355 33 100 66     203 if ( defined $self->{defs_module_name}
356             && $self->{defs_module_name} eq $defs_mod_name )
357             {
358 21         60 return $self->{defs_href};
359             }
360             } else {
361 0 0 0     0 if ( defined $defs_module_name && $defs_module_name eq $defs_mod_name ) {
362 0         0 return $info_href;
363             }
364             }
365             } ## end if ( !$b_force_reload )
366              
367             # Back up the Defs module name.
368 15 50       67 if ($self) {
369 15         46 $self->{defs_module_name} = $defs_mod_name;
370             } else {
371 0         0 $defs_module_name = $defs_mod_name;
372             }
373              
374             # my $info_path;
375             # if ( $BASE_DIR eq './' ) {
376             # $info_path = $DEFS_DIR . "/" . $DEFS_MOD_NAME . ".pm";
377             # } else {
378             # $info_path = $BASE_DIR . "/" . $DEFS_DIR . "/" . $DEFS_MOD_NAME . ".pm";
379             # }
380              
381             # Unload Defs module.
382 15 100       59 if ($b_force_reload) {
383 3         11 _unload_module($defs_mod_name);
384             }
385 15         156 my $proc = Su::Process->new;
386 15         88 $proc->load_module($defs_mod_name);
387              
388             # require $defs_mod_name;
389              
390 15 50       52 if ($self) {
391 15         88 $self->{defs_href} = $defs_mod_name->defs;
392             } else {
393 0         0 $info_href = $defs_mod_name->defs;
394             }
395 15         1002 return $defs_mod_name->defs;
396              
397             } ## end sub _load_defs_file
398              
399             =item setup()
400              
401             Instead of loading the definition form the Definition file, this method set the definition directly.
402              
403             Su::setup(
404             menu =>{proc=>'MenuTmpl', model=>qw(main sites about)},
405             book_comp =>{proc=>'BookTmpl', model=>'MenuModel'},
406             menuWithArg =>{proc=>'MenuTmplWithArg', model=>{field1=>{type=>'string'},field2=>{type=>'number'}}},
407             );
408              
409             =cut
410              
411             sub setup {
412 4 50   4 1 1680 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
413              
414 4 100       17 if ( ref $_[0] eq 'HASH' ) {
415 2         5 $info_href = shift;
416             } else {
417 2         10 my %h = @_;
418 2         9 $info_href = \%h;
419             }
420              
421             } ## end sub setup
422              
423             =item new()
424              
425             Instantiate the Su instance.
426             To make Su instance recognize the custom definition module, you can
427             pass the package name of the definition file as a parameter.
428              
429             my $su = Su->new;
430              
431             my $su = Su->new('Pkg::Defs');
432              
433             my $su = Su->new(defs_module=>'Pkg::Defs');
434              
435             =cut
436              
437             sub new {
438 16     16 1 414549 my $self = shift;
439              
440 16 50       86 if ( scalar @_ == 1 ) {
441 0         0 my $defs_id = $_[0];
442 0         0 my $tmp_ref = \$defs_id;
443 0 0       0 if ( ref $tmp_ref eq 'SCALAR' ) {
444 0         0 return bless { defs_module => $defs_id }, $self;
445             }
446 0         0 croak "invalid new parameter:" . @_;
447             } ## end if ( scalar @_ == 1 )
448             else {
449 16         68 my %h = @_;
450 16         80 return bless \%h, $self;
451             }
452              
453             } ## end sub new
454              
455             =item resolve()
456              
457             Find the passed id from the definition file and execute the
458             corresponding Process after the injection of the corresponding Model to
459             the Process.
460              
461             An example of the definition in F is like the following.
462              
463             my $defs =
464             {
465             entry_id =>
466             {
467             proc=>'Pkg::SomeProc',
468             model=>'Pkg::SomeModel',
469             },
470             };
471              
472             Note that C field in the definition file is required, but
473             C field can omit. To execute the process descired in this
474             example, your code will become like the following.
475              
476             my $ret = $su->resolve('entry_id');
477              
478             If you pass the additional parameters to the resolve method, these
479             parameters are passed to the C method of the Process.
480              
481             my $ret = $su->resolve('entry_id', 'param_A', 'param_B');
482              
483             If the passed entry id is not defined in Defs file, then the error is thorwn.
484              
485             Definition can be also specified as a parameter of the C method like the following.
486              
487             $su->resolve({
488             proc=>'MainProc',
489             model=>['Model01','Model02','Model03'],
490             });
491              
492             $su->resolve(
493             {
494             proc => 'Sample::Procs::SomeModule',
495             model => { key1 => { 'nestkey1' => ['value'] } },
496             },
497             'arg1',
498             'arg2');
499              
500             B
501              
502             This method works differently according to the style of the model definition.
503              
504             If the C field is a string, then Su treat it as a name of the Model, load
505             it's class and set it's C field to the Process.
506              
507             some_entry_id =>{proc=>'ProcModule', model=>'ModelModule'},
508              
509             If the C field is a hash, Su set it's hash to the C field of
510             the Process directly.
511              
512             some_entry_id =>{proc=>'ProcModule', model=>{key1=>'value1',key2=>'value2'}},
513              
514             If the C field is a reference of the string array, then Su load each
515             element as Model module and execute Process with each model.
516              
517             some_entry_id =>{proc=>'TmplModule', model=>['ModelA', 'ModelB', 'ModelC']},
518              
519             In this case, Process is executed with each Model, and the array of
520             each result is returned.
521              
522             B
523              
524             If a definition has any filter related fields, then these filter
525             methods are applied before Su return the result of the process method.
526             The module specified as a filter must has the method which corresponds
527             to the filter type. About usable filter types, see the section of
528             C, C, C.
529              
530             These filter methods receive the result of the process or previous
531             filter as a parameter, and return the filtered result to the caller or
532             next filter.
533              
534             Following is an example of the definition file to use post filter.
535              
536             my $defs =
537             {
538             exec_post_filter =>
539             {
540             proc=>'MainProc',
541             model=>['Model01','Model02','Model03'],
542             post_filter=>'FilterProc'
543             },
544              
545             Multiple filters can be set to the definition file.
546              
547             exec_post_filter_chain =>
548             {
549             proc=>'MainProc',
550             model=>['Model01','Model02','Model03'],
551             post_filter=>['FilterProc1', 'FilterProc1']
552             }
553             };
554              
555             An example of the C method in the filter class is the following.
556             The C receives an array of previous result as a parameter and
557             return the result as an array.
558              
559             sub map_filter {
560             my $self = shift if ref $_[0] eq __PACKAGE__;
561             my @results = @_;
562            
563             for (@results) {
564             # Do some filter process.
565             }
566             return @results;
567             }
568              
569             An example of the C method in the filter class is the
570             following. The C receives an array as a parameter and
571             return the result as a scalar.
572              
573             sub reduce_filter {
574             my $self = shift if ref $_[0] eq __PACKAGE__;
575             my @results = @_;
576            
577             # For example, just join the result and return.
578             return join( ',', @results );
579             }
580              
581             An example of the C method in the filter class is the
582             following. The C receives a scalar as a parameter and
583             return the result as a scalar.
584              
585             sub scalar_filter {
586             my $self = shift if ref $_[0] eq __PACKAGE__;
587             my $result = shift;
588            
589             # Do some filter process to the $result.
590            
591             return $result;
592             }
593              
594             This method change the Model file to load by the specified locale.
595              
596             If you specify the resource locale to $Su::MODEL_LOCALE, this method
597             load locale specific Model automatically, and locale specific Model
598             is not exist, then this method tring to load default Model.
599              
600             Set the locale variable like the following:
601              
602             $Su::MODEL_LOCALE = 'ja_JP';
603              
604             The name of locale specific Model is like the following:
605              
606             pkg::SomeModel__ja_JP
607              
608             And the file name becomes like this.
609              
610             pkg/SomeModel__ja_JP.pm
611              
612             =cut
613              
614             sub resolve {
615 45 100   45 1 21045 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
616              
617 45         83 my $comp_id = shift;
618 45         91 my @ctx = @_;
619              
620             my ( $info_href, $new_comp_id ) =
621 45 100 100     208 ( $self && eval { $self->isa('Su') } )
622             ? $self->_get_info($comp_id)
623             : _get_info($comp_id);
624 43 100       124 $comp_id = $new_comp_id if $new_comp_id;
625              
626             # If Su->{base} is specified, this effects to Template and Model, else used own value Template and Model has.
627 43         100 my $BASE_DIR = $self->{base};
628 43 50       122 my $MODEL_DIR = $self->{model} ? $self->{model} : $Su::Model::MODEL_DIR;
629 43 50       110 my $TEMPLATE_DIR =
630             $self->{template} ? $self->{template} : $Su::Template::TEMPLATE_DIR;
631              
632 43         240 my $proc = Su::Process->new( base => $BASE_DIR, dir => $TEMPLATE_DIR );
633 43         113 my $proc_id = $info_href->{$comp_id}->{proc};
634 43 50       261 croak 'proc not set in '
    100          
635             . (
636             $self->{defs_module_name}
637             ? $self->{defs_module_name} . ":${comp_id}"
638             : 'the passed definition'
639             )
640             . '.'
641             unless $proc_id;
642 42         138 my $tmpl_module = $proc->load_module($proc_id);
643              
644             # Save executed module to the instance.
645 42 50       163 $self->{module} = $tmpl_module if $self;
646              
647 42         86 my @ret_arr = ();
648              
649             # Still not refactored!
650              
651             # If the setter method of the field 'model' exists.
652 42 100       388 if ( $tmpl_module->can('model') ) {
653              
654             # model is hash reference. so pass it direct.
655 37 100       178 if ( ref $info_href->{$comp_id}->{model} eq 'HASH' ) {
    100          
656 4         15 $tmpl_module->model( $info_href->{$comp_id}->{model} );
657             } elsif ( ref $info_href->{$comp_id}->{model} eq 'ARRAY' ) {
658              
659             } else {
660              
661             # this should be model class name.
662              
663 30         182 my $mdl = Su::Model->new( base => $BASE_DIR, dir => $MODEL_DIR );
664 30         77 my $loading_model = $info_href->{$comp_id}->{model};
665 30         69 chomp $loading_model;
666              
667             # Add locale postfix if postfix is specified.
668 30         41 my $base_loading_model = $loading_model;
669 30 100       87 $loading_model .= '__' . $Su::MODEL_LOCALE if ($Su::MODEL_LOCALE);
670              
671             # If locale specific model is not exist, then load default model file.
672 30         167 Su::Log->trace( 'loading model:' . $loading_model );
673 30 50       103 if ($loading_model) {
674 30         141 my $model = $mdl->load_model( $loading_model, { suppress_error => 1 } );
675 30 100       111 $model = $mdl->load_model($base_loading_model) unless $model;
676              
677             # Load global field from Defs file.
678 30 100       128 %{$model} = ( %{$model}, %{ $info_href->{$GLOBAL_MODEL_FIELD} } )
  2         5  
  2         6  
  2         5  
679             if defined $info_href->{$GLOBAL_MODEL_FIELD};
680              
681             # Get the prefix or postfix setting for loading model.
682 30   100     139 my $MODEL_KEY_PREFIX = $MODEL_KEY_PREFIX->{$loading_model} || '';
683 30   100     126 my $MODEL_KEY_POSTFIX = $MODEL_KEY_POSTFIX->{$loading_model} || '';
684              
685             # If the key prefix or postfix is specified, copy the value of the
686             # modified key to original key value.
687 30 100 100     144 if ( $MODEL_KEY_PREFIX || $MODEL_KEY_POSTFIX ) {
688 3         5 my $new_model = {};
689 3         5 foreach my $key ( keys %{$model} ) {
  3         14  
690 12 100       55 if (
    100          
    100          
691             exists $model->{ $MODEL_KEY_PREFIX . '__'
692             . $key . '__'
693             . $MODEL_KEY_POSTFIX } )
694             {
695 1         6 $new_model->{$key} =
696             $model->{ $MODEL_KEY_PREFIX . '__'
697             . $key . '__'
698             . $MODEL_KEY_POSTFIX };
699             } elsif ( exists $model->{ $MODEL_KEY_PREFIX . '__' . $key } ) {
700 3         11 $new_model->{$key} = $model->{ $MODEL_KEY_PREFIX . '__' . $key };
701             } elsif ( exists $model->{ $key . '__' . $MODEL_KEY_POSTFIX } ) {
702 3         12 $new_model->{$key} = $model->{ $key . '__' . $MODEL_KEY_POSTFIX };
703             } else {
704 5         14 $new_model->{$key} = $model->{$key};
705             }
706             } ## end foreach my $key ( keys %{$model...})
707 3         8 $model = $new_model;
708             } ## end if ( $MODEL_KEY_PREFIX...)
709 30         114 $tmpl_module->model($model);
710              
711             } ## end if ($loading_model)
712             } ## end else [ if ( ref $info_href->{...})]
713             } ## end if ( $tmpl_module->can...)
714              
715             # Just return proc instance.
716 42 100       579 if ( $self->{just_return_module} ) {
717 3         22 return $tmpl_module;
718             }
719              
720 39 100       185 if ( $tmpl_module->can('model') ) {
721 34 100       126 if ( ref $info_href->{$comp_id}->{model} eq 'ARRAY' ) {
722              
723             # Call module method with each of models.
724 3         25 my $mdl = Su::Model->new( base => $BASE_DIR, dir => $MODEL_DIR );
725              
726 3         7 for my $loaded_model ( @{ $info_href->{$comp_id}->{model} } ) {
  3         11  
727              
728             #diag("model:" . $info_href->{$comp_id}->{model});
729             #diag("loaded:" . $mdl->load_model($info_href->{$comp_id}->{model}));
730 9         46 chomp $loaded_model;
731 9 50       20 if ($loaded_model) {
732 9         48 $tmpl_module->model( $mdl->load_model($loaded_model) );
733 9         87 push @ret_arr, $tmpl_module->process(@ctx);
734             }
735             } ## end for my $loaded_model ( ...)
736              
737             } ## end if ( ref $info_href->{...})
738             } ## end if ( $tmpl_module->can...)
739              
740 39         112 my @filters = ();
741 39         46 my $reduce_filter;
742 39         59 my @scalar_filters = ();
743              
744             # Collect post filters.
745 39 100       154 if ( $info_href->{$comp_id}->{map_filter} ) {
746              
747             # The single filter is set as class name string.
748 5 50       16 if ( ref $info_href->{$comp_id}->{map_filter} eq '' ) {
    0          
749 5         12 push @filters, $info_href->{$comp_id}->{map_filter};
750             } elsif ( ref $info_href->{$comp_id}->{map_filter} eq 'ARRAY' ) {
751              
752             # The filters are set as array reference.
753 0         0 @filters = @{ $info_href->{$comp_id}->{map_filter} };
  0         0  
754             }
755              
756             } ## end if ( $info_href->{$comp_id...})
757              
758             # Collect reduce filter.
759             # Note:Multiple reduce filter not permitted to set.
760 39 100       111 if ( $info_href->{$comp_id}->{reduce_filter} ) {
761              
762             # The single filter is set as class name string.
763 2 50       7 if ( ref $info_href->{$comp_id}->{reduce_filter} eq '' ) {
764 2         5 $reduce_filter = $info_href->{$comp_id}->{reduce_filter};
765             }
766             } ## end if ( $info_href->{$comp_id...})
767              
768             # Collect scalar filters
769 39 100       102 if ( $info_href->{$comp_id}->{scalar_filter} ) {
770              
771             # The single filter is set as class name string.
772 3 50       9 if ( ref $info_href->{$comp_id}->{scalar_filter} eq '' ) {
    0          
773 3         7 push @scalar_filters, $info_href->{$comp_id}->{scalar_filter};
774             } elsif ( ref $info_href->{$comp_id}->{scalar_filter} eq 'ARRAY' ) {
775              
776             # The filters are set as array reference.
777 0         0 @scalar_filters = $info_href->{$comp_id}->{scalar_filter};
778             }
779              
780             } ## end if ( $info_href->{$comp_id...})
781              
782             # Multiple data process return it's result array.
783 39 100       118 if (@ret_arr) {
784 3         7 for my $elm (@filters) {
785 1         8 my $tmpl_filter_module =
786             $proc->load_module( $info_href->{$comp_id}->{map_filter} );
787 1         8 @ret_arr = $tmpl_filter_module->map_filter(@ret_arr);
788             }
789              
790             #Todo: Multiple data process not implemented to apply reduce filter and scalar filter.
791 3         90 return @ret_arr;
792             } ## end if (@ret_arr)
793              
794 36         121 my @single_ret_arr = ( $tmpl_module->process(@ctx) );
795              
796             # Apply map filters.
797 36         289 for my $elm (@filters) {
798 4         17 my $tmpl_filter_module = $proc->load_module($elm);
799 4         18 @single_ret_arr = $tmpl_filter_module->map_filter(@single_ret_arr);
800             }
801              
802 36 100 100     501 return ( scalar @single_ret_arr == 1 ? $single_ret_arr[0] : @single_ret_arr )
    100          
803             unless ( $reduce_filter or @scalar_filters );
804              
805 4         5 my $reduced_result = '';
806              
807             # Apply reduce filter once.
808 4 100       12 if ($reduce_filter) {
    100          
809 2         6 my $reduce_filter_module = $proc->load_module($reduce_filter);
810 2         7 $reduced_result = $reduce_filter_module->reduce_filter(@single_ret_arr);
811             } elsif ( scalar @single_ret_arr == 1 ) {
812 1         3 $reduced_result = $single_ret_arr[0];
813             } else {
814 1         185 croak
815             "[ERROR]Can't apply scalar filter(s), because the result of the process is multiple and not reduced by the reduce filter";
816             }
817              
818             #Apply scalar filter to the single process result.
819 3         21 for my $elm (@scalar_filters) {
820 2         7 my $tmpl_filter_module = $proc->load_module($elm);
821 2         8 $reduced_result = $tmpl_filter_module->scalar_filter($reduced_result);
822             }
823 3         38 return $reduced_result;
824              
825             } ## end sub resolve
826              
827             =begin comment
828              
829             Read Process and Model infomation from Defs file.
830              
831             =end comment
832              
833             =cut
834              
835             sub _get_info {
836 45 100   45   149 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
837 45         62 my $comp_id = shift;
838 45         58 my $info_href;
839              
840             # If the flag $USE_GLOBAL_SETUP is set, use the setting set by the
841             # method Su::setup.
842 45 100 66     398 if ($USE_GLOBAL_SETUP) {
    100 66        
843 8         9 $info_href = $Su::info_href;
844             } elsif ( $self
845             && UNIVERSAL::isa( $self, 'UNIVERSAL' )
846             && $self->isa('Su') )
847             {
848              
849             # If hash is passed, just use passed info, and not load defs file.
850 31 100       203 $self->_load_defs_file( $self->{defs_module} )
851             unless ref $comp_id eq 'HASH';
852             } else {
853              
854             # called as global method like 'Su::resolve("id")'.
855 6 50       16 unless ( ref $comp_id eq 'HASH' ) {
856              
857             # If Su::setup is called, then use global setting, else load setting
858             # from defs file.
859 6         24 $info_href =
860 6 100       9 keys %{$Su::info_href} ? $Su::info_href : _load_defs_file();
861              
862             # _load_defs_file();
863 6         39 Su::Log->trace( 'comp_id:' . $comp_id );
864 6         27 Su::Log->trace( 'new set:' . Dumper($info_href) );
865             } ## end unless ( ref $comp_id eq 'HASH')
866              
867             # _load_defs_file();
868             } ## end else [ if ($USE_GLOBAL_SETUP)]
869              
870             # If defs info is passed as paramter, then use it.
871 45 100       333 if ( ref $comp_id eq 'HASH' ) {
    100          
872 7         59 $info_href = { 'dmy_id' => $comp_id };
873              
874             # Set dummy id to use passed parameter.
875 7         11 $comp_id = 'dmy_id';
876             } elsif ( !$info_href ) {
877              
878             # $self->{defs_href} and $Su::info_href is set by _load_defs_file().
879 25 50       76 $info_href = $self->{defs_href} ? $self->{defs_href} : $Su::info_href;
880             }
881              
882 45 100 33     268 if (
      66        
883 43         229 !$info_href->{$comp_id}
884             || !(
885             ref $info_href->{$comp_id} eq 'HASH' && keys %{ $info_href->{$comp_id} }
886             )
887             )
888             {
889 2         12 croak "Entry id '$comp_id' is not found in Defs file:"
890             . Dumper($info_href);
891             } ## end if ( !$info_href->{$comp_id...})
892              
893 43 100       276 return ( $info_href, $comp_id eq 'dmy_id' ? $comp_id : 0 );
894              
895             } ## end sub _get_info
896              
897             =item get_proc()
898              
899             This function is just a synonym of the method L.
900              
901             =cut
902              
903             sub get_proc {
904 1 50   1 1 9 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
905 1         2 my $ret;
906 1 50       8 if ($self) {
907 1         6 $ret = $self->get_instance(@_);
908             } else {
909 0         0 $ret = get_instance(@_);
910             }
911 1         4 return $ret;
912             } ## end sub get_proc
913              
914             =item
915              
916             Just return the instance of the Process which defined in Defs
917             file. Model data is set to that returned Process.
918              
919             my $proc = $su->get_instance('main_proc');
920              
921             =cut
922              
923             sub get_instance {
924 3 50   3 0 1644 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
925 3         7 my $comp_id = shift;
926              
927             # just_return_module is a flag not to execute process and just return
928             # the instance of the process itself.
929 3         7 $self->{just_return_module} = 1;
930 3         12 my $proc = $self->resolve($comp_id);
931 3         6 $self->{just_return_module} = undef;
932 3         9 return $proc;
933             } ## end sub get_instance
934              
935             =item get_inst()
936              
937             This function is just a synonym of the method L.
938              
939             =cut
940              
941             sub get_inst {
942 0 0   0 1 0 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
943 0         0 my $ret;
944 0 0       0 if ($self) {
945 0         0 $ret = $self->get_instance(@_);
946             } else {
947 0         0 $ret = get_instance(@_);
948             }
949 0         0 return $ret;
950             } ## end sub get_inst
951              
952             =item retr()
953              
954             This function is just a synonym of the method L.
955              
956             =cut
957              
958             sub retr {
959 1 50   1 1 831 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
960 1         2 my $ret;
961 1 50       3 if ($self) {
962 1         6 $ret = $self->get_instance(@_);
963             } else {
964 0         0 $ret = get_instance(@_);
965             }
966 1         4 return $ret;
967             } ## end sub retr
968              
969             =item inst()
970              
971             This function is just a synonym of the method L.
972              
973             =cut
974              
975             sub inst {
976 0 0   0 1 0 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
977 0         0 my $ret;
978 0 0       0 if ($self) {
979 0         0 $ret = $self->get_instance(@_);
980             } else {
981 0         0 $ret = get_instance(@_);
982             }
983 0         0 return $ret;
984             } ## end sub inst
985              
986             =item init()
987              
988             Generate the initial files at once. The initial files are composed of
989             Defs, Model and Process module.
990              
991             Su::init('PkgName');
992              
993             This method can be called from command line like the following:
994              
995             perl -MSu=base,base/directory -e 'Su::init("Pkg::SomeModule")'
996              
997             =cut
998              
999             sub init {
1000 0 0   0 1 0 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1001 0         0 my $pkg = shift;
1002              
1003 0 0       0 die "The parameter package name is requqired." unless $pkg;
1004              
1005             # Note that the package of defs file is fixed and don't reflect the passed package name.
1006 13     13   120 no warnings qw(once);
  13         32  
  13         14447  
1007 0 0       0 if ($self) {
1008              
1009             # The method 'init' use the fixed module and method name. Only the package name can be specified.
1010 0         0 $self->gen_defs( package => $pkg );
1011 0         0 $self->gen_model("${pkg}::${DEFAULT_MODEL_NAME}");
1012 0         0 $self->gen_proc("${pkg}::${DEFAULT_PROC_NAME}");
1013             } else {
1014 0         0 gen_defs( package => $pkg );
1015 0         0 gen_model("${pkg}::Model");
1016 0         0 gen_proc("${pkg}::MainProc");
1017              
1018             } ## end else [ if ($self) ]
1019              
1020             } ## end sub init
1021              
1022             =item gen_model()
1023              
1024             Generate a Model file.
1025              
1026             Su::gen_model("SomePkg::SomeModelName")
1027              
1028             perl -MSu=base,./lib/ -e 'Su::gen_model("Pkg::ModelName")'
1029              
1030             =cut
1031              
1032             sub gen_model {
1033 3 50   3 1 16 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1034 3 50       17 my $BASE_DIR = $self->{base} ? $self->{base} : $BASE_DIR;
1035 3         32 my $mdl = Su::Model->new( base => $BASE_DIR );
1036 3         17 $mdl->generate_model(@_);
1037              
1038             } ## end sub gen_model
1039              
1040             =item gen_proc()
1041              
1042             Generate a Process file.
1043              
1044             perl -MSu=base,./lib/ -e 'Su::gen_proc("Pkg::TestProc")'
1045              
1046             =cut
1047              
1048             sub gen_proc {
1049 3 50   3 1 11 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1050 3 50       12 my $BASE_DIR = $self->{base} ? $self->{base} : $BASE_DIR;
1051 3         19 my $proc = Su::Process->new( base => $BASE_DIR );
1052 3         15 $proc->generate_proc(@_);
1053              
1054             # my $generated_file = $proc->generate_proc(@_);
1055              
1056             } ## end sub gen_proc
1057              
1058             =item generate()
1059              
1060             Generate a pair of Process and Model file.
1061              
1062             my $su = Su->new;
1063             $su->generate('pkg::SomeProc');
1064              
1065             This example generates C and C.
1066              
1067             You can use this method from the commandline.
1068              
1069             perl -MSu=base,lib -e 'Su::generate("Pkg::SomeProc", 1)'
1070             perl -MSu=base,lib -e 'Su::generate("Pkg::SomeProc", "Defs::MyDefs")'
1071              
1072             If the second parameter is specified, the Defs file will generated.
1073              
1074             =cut
1075              
1076             sub generate {
1077 3 50   3 1 2542 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1078 3         5 my $fqcn = shift;
1079 3         6 my $gen_def = shift;
1080              
1081             # Save original fqcn.
1082 3         7 my $proc_fqcn = $fqcn;
1083 3         4 my $model_fqcn;
1084              
1085 3 50       10 return unless $fqcn;
1086              
1087             # Generate process.
1088 3 50       18 my $proc_fname = $self ? $self->gen_proc($fqcn) : gen_proc($fqcn);
1089              
1090             # Check whether the parameter has the postfix 'Proc'.
1091 3 100       19 if ( $fqcn =~ /.+Proc$/ ) {
1092              
1093             # Replace 'Proc' postfix to 'Model' to generate Model file.
1094 1         10 $fqcn =~ s/(.+)Proc$/$1Model/;
1095             } else {
1096              
1097             # Just add the postfix 'Model' to the passed param.
1098 2         8 $fqcn .= "Model";
1099             }
1100 3         5 $model_fqcn = $fqcn;
1101              
1102             # Generate model.
1103 3 50       21 my $model_fname = $self ? $self->gen_model($fqcn) : gen_model($fqcn);
1104              
1105 3         27 $proc_fname =~ s/\.pm$//;
1106 3         18 $proc_fname =~ s!/!::!g;
1107              
1108 3         15 $model_fname =~ s/\.pm$//;
1109 3         15 $model_fname =~ s!/!::!g;
1110              
1111 3 50       35 my $defs_fname = _is_string($gen_def) ? $gen_def : 'Defs::Defs';
1112              
1113             # Generate defs file.
1114 3 50 66     24 if (
    50          
1115             $gen_def
1116             || (
1117             $self ? $self->_is_defs_exist($defs_fname) : _is_defs_exist($defs_fname) )
1118             )
1119             {
1120 3         15 my @pkg_arr = split( '::', $fqcn );
1121 3         12 my $pkg = @pkg_arr[ 0 .. ( scalar @pkg_arr - 2 ) ];
1122              
1123 3 50       8 if ($self) {
1124 3         20 $self->gen_defs(
1125             name => $defs_fname,
1126              
1127             # package => $pkg,
1128             proc => $proc_fqcn,
1129             model => $model_fqcn,
1130             just_add_entry_if_defs_already_exist => 1,
1131             use_proc_name_as_entry_id => 1,
1132             );
1133              
1134             # $self->gen_defs( package => $defs_fname );
1135             } else {
1136 0         0 gen_defs(
1137             name => $defs_fname,
1138              
1139             # package => $pkg,
1140             proc => $proc_fqcn,
1141             model => $model_fqcn,
1142             just_add_entry_if_defs_already_exist => 1,
1143             use_proc_name_as_entry_id => 1,
1144             );
1145              
1146             } ## end else [ if ($self) ]
1147             } ## end if ( $gen_def || ( $self...))
1148             else {
1149 0         0 my $entry_id = _make_entry_id($proc_fqcn);
1150 0         0 my $output = <<"__HERE__";
1151             An example of the entry to add to the Defs file.
1152              
1153             $entry_id => {
1154             proc => '$proc_fqcn',
1155             model => '$model_fqcn',
1156             },
1157             __HERE__
1158              
1159 0         0 print $output;
1160             } ## end else [ if ( $gen_def || ( $self...))]
1161             } ## end sub generate
1162              
1163             =item gen_defs()
1164              
1165             Generate a definition file.
1166              
1167             perl -MSu=base,./lib/ -e 'Su::gen_defs()'
1168              
1169             You can specify the package name of the definition file as a parameter.
1170              
1171             gen_defs('Defs::Defs');
1172              
1173             Also you can specify other parameters as a hash.
1174              
1175             gen_defs(name=>'Defs::Defs',
1176             package=>'pkg',
1177             proc=>'MyProc',
1178             model=>'MyModel',
1179             just_add_entry_if_defs_already_exist => 1,
1180             use_proc_name_as_entry_id => 1)
1181              
1182             param use_proc_name_as_entry_id:
1183             Set the proc name as entry id instead of default id 'main'.
1184              
1185             param just_add_entry_if_defs_already_exist:
1186             If the specified Defs file is already exist, then add the entry to that Defs file.
1187              
1188             return:
1189             1: If generation success.
1190             0: If the Defs file already exists.
1191              
1192             =cut
1193              
1194             sub gen_defs {
1195 6 50   6 1 2372 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1196              
1197 6 50       60 my $ret =
1198             $self
1199             ? $self->_gen_defs_with_template_id( 'DefsPm', @_ )
1200             : _gen_defs_with_template_id( 'DefsPm', @_ );
1201              
1202             # Exclude the case of single parameter.
1203 6 50       29 if ( scalar @_ != 1 ) {
1204 6         26 my %defs_h = @_;
1205 6 100 100     50 if ( $ret == 0 && !$defs_h{just_add_entry_if_defs_already_exist} ) {
1206 1         11 warn "[WARN] Defs file alredy exists.";
1207             }
1208             } ## end if ( scalar @_ != 1 )
1209 6         36 return $ret;
1210              
1211             } ## end sub gen_defs
1212              
1213             =begin comment
1214              
1215             param template_id: File name to load template string.
1216             return:
1217             1: If generation success.
1218             0: If the Defs file already exists.
1219              
1220             =end comment
1221              
1222             =cut
1223              
1224             sub _gen_defs_with_template_id {
1225 6 50   6   27 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1226 6         12 my $template_id = shift;
1227 6         8 my $template_string;
1228 13     13   100 use File::Basename;
  13         24  
  13         22717  
1229              
1230 6         413 my $template_fname =
1231             dirname(__FILE__) . $SU_TMPL_DIR . $template_id . '.tmpl';
1232              
1233 6 50       209 open( my $F, '<', $template_fname ) or die $! . ":$template_fname";
1234 6         832 $template_string = join '', <$F>;
1235              
1236 6 50       70 return $self
1237             ? $self->_gen_defs_internal( $template_string, @_ )
1238             : _gen_defs_internal( $template_string, @_ );
1239             } ## end sub _gen_defs_with_template_id
1240              
1241             =begin comment
1242              
1243             param1: Template string to expand.
1244             return:
1245             1: If generation success.
1246             0: If the Defs file already exists.
1247              
1248             =end comment
1249              
1250             =cut
1251              
1252             sub _gen_defs_internal {
1253 6 50   6   35 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1254 6         14 my $template_string = shift;
1255 6         13 my $defs_id;
1256             my %defs_h;
1257              
1258             # The single parameter is Defs file name.
1259 6 50       23 if ( scalar @_ == 1 ) {
1260 0   0     0 $defs_id = shift || $DEFS_MODULE_NAME;
1261             } else {
1262              
1263             # Else the hash of parameters.
1264 6         36 %defs_h = @_;
1265              
1266 6   66     54 $defs_id = $defs_h{name} || $defs_h{file_name} || $DEFS_MODULE_NAME;
1267              
1268             } ## end else [ if ( scalar @_ == 1 ) ]
1269              
1270 6 50       27 my $BASE_DIR = $self->{base} ? $self->{base} : $BASE_DIR;
1271 6 50       97 my $DEFS_DIR = $self->{defs} ? $self->{defs} : $DEFS_DIR;
1272              
1273             # Make directory path.
1274 6         53 my @arr = split( '/|::', $defs_id );
1275 6         15 my $defs_base_name = '';
1276 6 100       23 if ( scalar @arr > 1 ) {
1277 3         13 $defs_base_name = join( '/', @arr[ 0 .. scalar @arr - 2 ] );
1278             }
1279              
1280 6         9 my $dir;
1281 6 100       35 if ( $defs_id =~ /::|\// ) {
1282 3         11 $dir = $BASE_DIR . "/" . $defs_base_name;
1283             } else {
1284 3         342 $dir = $BASE_DIR . "/" . $DEFS_DIR . "/" . $defs_base_name;
1285             }
1286              
1287             # Prepare directory for generate file.
1288 6 50       123 mkpath $dir unless ( -d $dir );
1289              
1290 6 50       82 if ( !-d $dir ) {
1291 0         0 die "Can't make dir:" . $!;
1292             }
1293              
1294 6         12 my $defs_id_filepath = $defs_id;
1295 6         22 $defs_id_filepath =~ s!::!/!g;
1296              
1297             # Generate file.
1298 6         10 my $fpath;
1299 6 100       31 if ( $defs_id =~ /::|\// ) {
1300 3         11 $fpath = $BASE_DIR . "/" . $defs_id_filepath . ".pm";
1301             } else {
1302 3         14 $fpath = $BASE_DIR . "/" . $DEFS_DIR . "/" . $defs_id_filepath . ".pm";
1303             }
1304              
1305 6         14 $defs_id =~ s/\//::/g;
1306              
1307 6 100       26 if ( $defs_id !~ /::/ ) {
1308 3         7 my $defs_dir_for_package = $DEFS_DIR;
1309 3         7 $defs_dir_for_package =~ s!/!::!g;
1310              
1311             #Note: Automatically add the default package Models.
1312 3         9 $defs_id = $defs_dir_for_package . '::' . $defs_id;
1313             } ## end if ( $defs_id !~ /::/ )
1314              
1315 6   66     31 my $defs_proc_name = $defs_h{proc} || $DEFAULT_PROC_NAME;
1316 6   66     24 my $defs_model_name = $defs_h{model} || $DEFAULT_MODEL_NAME;
1317 6   50     74 my $pkg = $defs_h{package} || $defs_h{pkg} || "";
1318 6         14 my $main_entry_id = 'main';
1319              
1320             # If the Defs file is already exist.
1321 6 100       109 if ( -f $fpath ) {
1322              
1323             # Add the entry to the Defs file which already exists.
1324 3 100       14 if ( $defs_h{just_add_entry_if_defs_already_exist} ) {
1325              
1326 2         9 my $entry_id = _make_entry_id($defs_proc_name);
1327 2         51 open( my $I, $fpath );
1328 2         171 my $content = join '', <$I>;
1329 2         29 close $I;
1330 2         11 my $tmpl_str = <<"__HERE__";
1331             ,
1332             ${entry_id} =>
1333             {
1334             proc=>"${pkg}${defs_proc_name}",
1335             model=>"${pkg}${defs_model_name}",
1336             },
1337             __HERE__
1338              
1339 2         24 $content =~ s/(# \[The mark to add the entries\])/$tmpl_str\n$1/;
1340              
1341 2         48 open( my $FO, '>', $fpath );
1342 2         242 print $FO $content;
1343 2         85 close $FO;
1344             } else {
1345              
1346             # Do Nothing.
1347             }
1348 3         55 return 0;
1349             } ## end if ( -f $fpath )
1350              
1351             # Make entry id.
1352 3 100       13 if ( $defs_h{use_proc_name_as_entry_id} ) {
1353 1         6 $main_entry_id = _make_entry_id($defs_proc_name);
1354             }
1355              
1356 3         85 open( my $file, '>', $fpath );
1357              
1358 3         367 my $ft = Su::Template->new;
1359              
1360 13     13   95 use Data::Dumper;
  13         32  
  13         6136  
1361              
1362             # Make package name, else remain empty.
1363 3 50       13 $pkg = $pkg ? ( $pkg . '::' ) : '';
1364              
1365 3         17 my $contents =
1366             $ft->expand( $template_string, $defs_id, $pkg, $defs_proc_name,
1367             $defs_model_name, $main_entry_id );
1368              
1369 3         71 print $file $contents;
1370 3         357 return 1;
1371              
1372             } ## end sub _gen_defs_internal
1373              
1374             =begin comment
1375              
1376             Return 1 if the type of the passed argment is a string.
1377             If the parameter type is a number or reference then this method return 0.
1378             If the string "true" is passed, this method return 0;
1379              
1380             =end comment
1381              
1382             =cut
1383              
1384             sub _is_string {
1385 3     3   5 my $arg = shift;
1386 3 50 66     31 if ( $arg && ( $arg ^ $arg ) ne '0' && !( ref $arg ) && $arg ne 'true' ) {
      33        
      33        
1387 0         0 return 1;
1388             } else {
1389 3         13 return 0;
1390             }
1391              
1392             } ## end sub _is_string
1393              
1394             =begin comment
1395              
1396             Extract the class name from the passed parameter and make lower case it's firsr charactor.
1397              
1398             param: The string of fully qualified name.
1399             return: The class name converted to lower case of it's first charactor.
1400              
1401             =end comment
1402              
1403             =cut
1404              
1405             sub _make_entry_id {
1406 3     3   7 my $arg = shift;
1407 3         16 my @name_elem = split( '::', $arg );
1408 3         18 return lcfirst $name_elem[ scalar @name_elem - 1 ];
1409              
1410             } ## end sub _make_entry_id
1411              
1412             =begin comment
1413              
1414             Return 1 if passed argument is reference of empty hash.
1415             Note that if argument type is not reference, then return 1;
1416             Non-hash type parameter also return 1.
1417              
1418             Note: Currently not used.
1419              
1420             =end comment
1421              
1422             =cut
1423              
1424             # sub is_hash_empty {
1425             # my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1426             # my $href = shift;
1427             # return 1 if ( !$href );
1428             # if ( ref $href eq 'HASH' ) {
1429             # if ( keys %{$href} ) {
1430             # return 0;
1431             # } else {
1432             # return 1;
1433             # }
1434             # } ## end if ( ref $href eq 'HASH')
1435             # return 1;
1436             # } ## end sub is_hash_empty
1437              
1438             =begin comment
1439              
1440             Unload the passed module.
1441              
1442             _unload_module('Defs::Defs.pm');
1443              
1444             =end comment
1445              
1446             =cut
1447              
1448             sub _unload_module {
1449 3 50   3   14 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1450 3         5 my $fqmn = shift;
1451 3         14 my @path_elems = split '::', $fqmn;
1452              
1453             {
1454 13     13   101 no strict 'refs';
  13         46  
  13         5177  
  3         10  
1455 3         5 @{ $fqmn . '::ISA' } = ();
  3         68  
1456 3         7 %{ $fqmn . '::' } = ();
  3         69  
1457 3         7 delete ${ ( join '::', @path_elems[ 0 .. $#path_elems - 1 ] ) . '::' }
  3         46  
1458             { $path_elems[-1] . '::' };
1459 3         26 delete $INC{ ( join '/', @path_elems ) . '.pm' };
1460             }
1461              
1462             } ## end sub _unload_module
1463              
1464             =begin comment
1465              
1466             Return true if the Defs file is exist.
1467              
1468             param: Defs module name or file path.
1469              
1470             return:
1471             1: If the Defs file exist.
1472             undef: If the Defs file not exist.
1473              
1474             =end comment
1475              
1476             =cut
1477              
1478             sub _is_defs_exist {
1479 1 50   1   6 my $self = shift if ( ref $_[0] eq __PACKAGE__ );
1480 1   33     5 my $defs_id = shift || $DEFS_MODULE_NAME;
1481              
1482 1 50       6 my $BASE_DIR = $self->{base} ? $self->{base} : $BASE_DIR;
1483 1 50       6 my $DEFS_DIR = $self->{defs} ? $self->{defs} : $DEFS_DIR;
1484              
1485 1         2 my $defs_id_filepath = $defs_id;
1486 1         4 $defs_id_filepath =~ s/::/\//;
1487 1         3 my $fpath;
1488 1 50       9 if ( $defs_id =~ /::|\// ) {
1489 1         4 $fpath = $BASE_DIR . "/" . $defs_id_filepath . ".pm";
1490             } else {
1491 0         0 $fpath = $BASE_DIR . "/" . $DEFS_DIR . "/" . $defs_id_filepath . ".pm";
1492             }
1493 1         42 return -f $fpath;
1494             } ## end sub _is_defs_exist
1495              
1496             1;
1497              
1498             __END__