The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Su - A simple application layer to divide and integrate data and processes in the Perl program.

SYNOPSIS

 my $su = Su->new;
 my $proc_result = $su->resolve('process_id');
 print $proc_result;

DESCRIPTION

Su is a simple application framework that works as a thin layer to divide data and process in your Perl program. This framework aims an ease of maintenance and extension of your application.

Su is a thin application layer, so you can use Su with many other frameworks you prefer in many cases.

Note that Su framework has nothing to do with unix su (switch user) command.

Prepare Data and Process file

Su provides the method to generate the template of Model and Process. You can use method generate() like the following:

  perl -MSu -e 'Su::generate("Pkg::SomeProc")'

Then, the file Pkg/SomeProc.pm and Pkg/SomeModel.pm should be generated.

Now describe your data to the $model field of the generated Model file.

 my $model=
 {
   field_a =>'value_a'
 };

And describe your process code to the process method defined in the generated Process file like the following:

 sub process{
   my $self = shift if ref $_[0] eq __PACKAGE__;
   my $param = shift;

   my $ret = "param:" . $param . " and model:" . $model->{field_a};
   return $ret;
 }

Integrate Model and Process

Su integrates Model and Processes using the definition file. To generate the definition file, type the following command.

 perl -MSu -e 'Su::gen_defs()'

Then describe your setting to the $defs field defined in the generated Defs.pm file.

 my $defs =
   {
    some_entry_id =>
    {
     proc=>'Pkg::SomeProc',
     model=>'Pkg::SomeModel',
    },
   };

You can also generate Defs.pm using the generate method by passing the parameter 1 as a second parameter.

  perl -MSu=base,lib -e 'Su::generate("Pkg::SomeProc", 1)'

Then the file Defs.pm will be generated with Model and Process file.

Run the process using Su

You can call the process via Su by passing the entry id which defined in the definition file Defs.pm.

 my $su = Su->new;
 my $result = $su->resolve('some_entry_id');

To pass the parameters to the process method in Process, then pass the additional parameter to the resolve method.

 my $result = $su->resolve('some_entry_id', 'param1');

Other features Su provides

Logging and string template are the feature su provides for convinience. These features are frequently used in many kinds of applications and you can use these features without any other dependencies. Surely you can use other modules you prefer with Su framework.

Additional usage - Filters

The map, reduce and scalar filters can be defined in the definition file.

These filters are Perl module which has the method for filtering the result of the process. (In case of map filter, method name is map_filter.) You can chain filter modules. The following code is a sample definition which uses these filters.

  my $defs =
   {
    some_proc_id =>
    {
     proc=>'MainProc',
     model=>'Pkg::MainModel',
     map_filter=>'Pkg::FilterProc',     # or ['Filter01','Filter02']
     reduce_filter=>'Pkg::ReduceProc',  # reduce filter can only apply at once.
     scalar_filter=>'Pkg::ScalarProc',  # or ['Filter01','Filter02']
    }
   };

The filters Su recognizes are the followings.

map_filter

The perl module which has map_filter method. The parameter of this method is an array which is a result of the 'process' method of the Process or the chained map filter. The map_filter method must return the array data type.

reduce_filter

The perl module which has reduce_filter method. The parameter of this method is an array which is a result of the 'process' method of the Process. If the map filters are defined in the Defs.pm, then the map_filters are applied to the result of the process before passed to the reduce filter. The reduce_filter method must return the scalar data type. Note that this method can't chain.

scalar_filter

The perl module which has scalar_filter method. The parameter of this method is a scalar which is a result of the 'process' method of the Process. If the map_filters and recude_filters are defined in the Defs.pm, then these filters are applied to the result of the process before passed to the scalar filter.

The scalar_filter method must return the scalar data type.

ATTRIBUTES

$MODEL_LOCALE

Set the locale string like 'ja_JP' to load locale specific Model module. Locale specific Model has the postfix in it's name like 'Pkg::ModelName__ja_JP'.

Then you should set the locale like this.

  $Su::MODEL_LOCALE = 'ja_JP';

$MODEL_KEY_PREFIX

The hash reference which contains the key prefixes of the Model. The key of this hash is a name of the model to apply this prefix.

  $MODEL_KEY_PREFIX = {
    'pkg::SomeModel'=>'pre1',
  };

In this example, the key string 'pre1_key1' defined in 'pkg::SomeModel' is automatically converted to 'key1'. So you can access customized value using key 'key1'.

If the modified key is not exist, then the value of original key should used.

$MODEL_KEY_POSTFIX

The hash reference which contains the key postfixes of the Model. The key of this hash is a name of the model to apply this postfix.

This variable work same as $MODEL_KEY_PREFIX.

METHODS

import()

use Su base=>'./base', proc=>'tmpls', model=>'models', defs=>'defs';

If you want to specify some parameters from the command line, then it becomes like the following.

perl -Ilib -MSu=base,./base,proc,tmpls,defs,models -e '{print "do some work";}'

setup()

Instead of loading the definition form the Definition file, this method set the definition directly.

 Su::setup(
   menu =>{proc=>'MenuTmpl', model=>qw(main sites about)},
   book_comp =>{proc=>'BookTmpl', model=>'MenuModel'},
   menuWithArg =>{proc=>'MenuTmplWithArg', model=>{field1=>{type=>'string'},field2=>{type=>'number'}}},
  );
new()

Instantiate the Su instance. To make Su instance recognize the custom definition module, you can pass the package name of the definition file as a parameter.

my $su = Su->new;

my $su = Su->new('Pkg::Defs');

my $su = Su->new(defs_module=>'Pkg::Defs');

resolve()

Find the passed id from the definition file and execute the corresponding Process after the injection of the corresponding Model to the Process.

An example of the definition in Defs.pm is like the following.

 my $defs =
   {
    entry_id =>
    {
     proc=>'Pkg::SomeProc',
     model=>'Pkg::SomeModel',
    },
   };

Note that proc field in the definition file is required, but model field can omit. To execute the process descired in this example, your code will become like the following.

 my $ret = $su->resolve('entry_id');

If you pass the additional parameters to the resolve method, these parameters are passed to the process method of the Process.

 my $ret = $su->resolve('entry_id', 'param_A', 'param_B');

If the passed entry id is not defined in Defs file, then the error is thorwn.

Definition can be also specified as a parameter of the resolve method like the following.

   $su->resolve({
     proc=>'MainProc',
     model=>['Model01','Model02','Model03'],
    });

  $su->resolve(
  {
    proc  => 'Sample::Procs::SomeModule',
    model => { key1 => { 'nestkey1' => ['value'] } },
  },
  'arg1',
  'arg2');

Optional Usage - Model Definition

This method works differently according to the style of the model definition.

If the model field is a string, then Su treat it as a name of the Model, load it's class and set it's model field to the Process.

 some_entry_id =>{proc=>'ProcModule', model=>'ModelModule'},

If the model field is a hash, Su set it's hash to the model field of the Process directly.

 some_entry_id =>{proc=>'ProcModule', model=>{key1=>'value1',key2=>'value2'}},

If the model field is a reference of the string array, then Su load each element as Model module and execute Process with each model.

 some_entry_id =>{proc=>'TmplModule', model=>['ModelA', 'ModelB', 'ModelC']},

In this case, Process is executed with each Model, and the array of each result is returned.

Optional Usage - Filters

If a definition has any filter related fields, then these filter methods are applied before Su return the result of the process method. The module specified as a filter must has the method which corresponds to the filter type. About usable filter types, see the section of map_filter, reduce_filter, scalar_filter.

These filter methods receive the result of the process or previous filter as a parameter, and return the filtered result to the caller or next filter.

Following is an example of the definition file to use post filter.

 my $defs =
   {
    exec_post_filter =>
    {
     proc=>'MainProc',
     model=>['Model01','Model02','Model03'],
     post_filter=>'FilterProc'
    },

Multiple filters can be set to the definition file.

    exec_post_filter_chain =>
    {
     proc=>'MainProc',
     model=>['Model01','Model02','Model03'],
     post_filter=>['FilterProc1', 'FilterProc1']
    }
   };

An example of the map_filter method in the filter class is the following. The map_filter receives an array of previous result as a parameter and return the result as an array.

 sub map_filter {
   my $self = shift if ref $_[0] eq __PACKAGE__;
   my @results = @_;
 
   for (@results) {
     # Do some filter process.
   }
   return @results;
 }

An example of the reduce_filter method in the filter class is the following. The reduce_filter receives an array as a parameter and return the result as a scalar.

 sub reduce_filter {
   my $self = shift if ref $_[0] eq __PACKAGE__;
   my @results = @_;
 
   # For example, just join the result and return.
   return join( ',', @results );
 }

An example of the scalar_filter method in the filter class is the following. The scalar_filter receives a scalar as a parameter and return the result as a scalar.

 sub scalar_filter {
   my $self = shift if ref $_[0] eq __PACKAGE__;
   my $result = shift;
 
 # Do some filter process to the $result.
  
   return $result;
 }

This method change the Model file to load by the specified locale.

If you specify the resource locale to $Su::MODEL_LOCALE, this method load locale specific Model automatically, and locale specific Model is not exist, then this method tring to load default Model.

Set the locale variable like the following:

  $Su::MODEL_LOCALE = 'ja_JP';

The name of locale specific Model is like the following:

  pkg::SomeModel__ja_JP

And the file name becomes like this.

  pkg/SomeModel__ja_JP.pm
get_proc()

This function is just a synonym of the method get_instance.

Just return the instance of the Process which defined in Defs file. Model data is set to that returned Process.

  my $proc = $su->get_instance('main_proc');
get_inst()

This function is just a synonym of the method get_instance.

retr()

This function is just a synonym of the method get_instance.

inst()

This function is just a synonym of the method get_instance.

init()

Generate the initial files at once. The initial files are composed of Defs, Model and Process module.

 Su::init('PkgName');

This method can be called from command line like the following:

 perl -MSu=base,base/directory -e 'Su::init("Pkg::SomeModule")'
gen_model()

Generate a Model file.

 Su::gen_model("SomePkg::SomeModelName")

 perl -MSu=base,./lib/ -e 'Su::gen_model("Pkg::ModelName")'
gen_proc()

Generate a Process file.

 perl -MSu=base,./lib/ -e 'Su::gen_proc("Pkg::TestProc")'
generate()

Generate a pair of Process and Model file.

  my $su = Su->new;
  $su->generate('pkg::SomeProc');

This example generates pkg/SomeProc.pm and pkg/SomeModl.pm.

You can use this method from the commandline.

  perl -MSu=base,lib -e 'Su::generate("Pkg::SomeProc", 1)'
  perl -MSu=base,lib -e 'Su::generate("Pkg::SomeProc", "Defs::MyDefs")'

If the second parameter is specified, the Defs file will generated.

gen_defs()

Generate a definition file.

 perl -MSu=base,./lib/ -e 'Su::gen_defs()'

You can specify the package name of the definition file as a parameter.

 gen_defs('Defs::Defs');

Also you can specify other parameters as a hash.

 gen_defs(name=>'Defs::Defs',
          package=>'pkg',
          proc=>'MyProc',
          model=>'MyModel',
          just_add_entry_if_defs_already_exist => 1,
          use_proc_name_as_entry_id            => 1)

param use_proc_name_as_entry_id: Set the proc name as entry id instead of default id 'main'.

param just_add_entry_if_defs_already_exist: If the specified Defs file is already exist, then add the entry to that Defs file.

return: 1: If generation success. 0: If the Defs file already exists.

SEE ALSO

Su::Process,Su::Model,Su::Template,Su::Log

AUTHOR

lottz <lottzaddr@gmail.com>

LICENSE

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 914:

Expected text after =item, not a bullet